diff options
author | Ilia Mirkin <imirkin@alum.mit.edu> | 2014-01-19 04:18:15 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-01-22 22:39:15 -0500 |
commit | f87cd8b695d372087685976460fac1ec6ba2fca9 (patch) | |
tree | 8c46a2f23bc25618beb134bf3d7a11f0cf228e28 | |
parent | d5c1e84b3a130f0743b218b33ff7d9cb493ab5b4 (diff) |
drm/nouveau/devinit: lock/unlock crtc regs for all devices, not just pre-nv50
Also make nv_lockvgac work for nv50+ devices. This should fix
IO_CONDITION and related VBIOS opcodes that read/write the crtc regs.
See https://bugs.freedesktop.org/show_bug.cgi?id=60680
Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/vga.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/devinit/base.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h | 8 |
4 files changed, 35 insertions, 10 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c index 5a1c68474597..8836c3cb99c3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c | |||
@@ -138,10 +138,15 @@ nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value) | |||
138 | bool | 138 | bool |
139 | nv_lockvgac(void *obj, bool lock) | 139 | nv_lockvgac(void *obj, bool lock) |
140 | { | 140 | { |
141 | struct nouveau_device *dev = nv_device(obj); | ||
142 | |||
141 | bool locked = !nv_rdvgac(obj, 0, 0x1f); | 143 | bool locked = !nv_rdvgac(obj, 0, 0x1f); |
142 | u8 data = lock ? 0x99 : 0x57; | 144 | u8 data = lock ? 0x99 : 0x57; |
143 | nv_wrvgac(obj, 0, 0x1f, data); | 145 | if (dev->card_type < NV_50) |
144 | if (nv_device(obj)->chipset == 0x11) { | 146 | nv_wrvgac(obj, 0, 0x1f, data); |
147 | else | ||
148 | nv_wrvgac(obj, 0, 0x3f, data); | ||
149 | if (dev->chipset == 0x11) { | ||
145 | if (!(nv_rd32(obj, 0x001084) & 0x10000000)) | 150 | if (!(nv_rd32(obj, 0x001084) & 0x10000000)) |
146 | nv_wrvgac(obj, 1, 0x1f, data); | 151 | nv_wrvgac(obj, 1, 0x1f, data); |
147 | } | 152 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c index 6b23d9a0b953..8fa34e8152c2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <subdev/bios.h> | 27 | #include <subdev/bios.h> |
28 | #include <subdev/bios/init.h> | 28 | #include <subdev/bios/init.h> |
29 | #include <subdev/vga.h> | ||
29 | 30 | ||
30 | #include "priv.h" | 31 | #include "priv.h" |
31 | 32 | ||
@@ -38,6 +39,9 @@ _nouveau_devinit_fini(struct nouveau_object *object, bool suspend) | |||
38 | if (suspend) | 39 | if (suspend) |
39 | devinit->post = true; | 40 | devinit->post = true; |
40 | 41 | ||
42 | /* unlock the extended vga crtc regs */ | ||
43 | nv_lockvgac(devinit, false); | ||
44 | |||
41 | return nouveau_subdev_fini(&devinit->base, suspend); | 45 | return nouveau_subdev_fini(&devinit->base, suspend); |
42 | } | 46 | } |
43 | 47 | ||
@@ -61,6 +65,17 @@ _nouveau_devinit_init(struct nouveau_object *object) | |||
61 | return 0; | 65 | return 0; |
62 | } | 66 | } |
63 | 67 | ||
68 | void | ||
69 | _nouveau_devinit_dtor(struct nouveau_object *object) | ||
70 | { | ||
71 | struct nouveau_devinit *devinit = (void *)object; | ||
72 | |||
73 | /* lock crtc regs */ | ||
74 | nv_lockvgac(devinit, true); | ||
75 | |||
76 | nouveau_subdev_destroy(&devinit->base); | ||
77 | } | ||
78 | |||
64 | int | 79 | int |
65 | nouveau_devinit_create_(struct nouveau_object *parent, | 80 | nouveau_devinit_create_(struct nouveau_object *parent, |
66 | struct nouveau_object *engine, | 81 | struct nouveau_object *engine, |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c index 24025e4e882a..7037eae46e44 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c | |||
@@ -388,17 +388,21 @@ int | |||
388 | nv04_devinit_fini(struct nouveau_object *object, bool suspend) | 388 | nv04_devinit_fini(struct nouveau_object *object, bool suspend) |
389 | { | 389 | { |
390 | struct nv04_devinit_priv *priv = (void *)object; | 390 | struct nv04_devinit_priv *priv = (void *)object; |
391 | int ret; | ||
391 | 392 | ||
392 | /* make i2c busses accessible */ | 393 | /* make i2c busses accessible */ |
393 | nv_mask(priv, 0x000200, 0x00000001, 0x00000001); | 394 | nv_mask(priv, 0x000200, 0x00000001, 0x00000001); |
394 | 395 | ||
395 | /* unlock extended vga crtc regs, and unslave crtcs */ | 396 | ret = nouveau_devinit_fini(&priv->base, suspend); |
396 | nv_lockvgac(priv, false); | 397 | if (ret) |
398 | return ret; | ||
399 | |||
400 | /* unslave crtcs */ | ||
397 | if (priv->owner < 0) | 401 | if (priv->owner < 0) |
398 | priv->owner = nv_rdvgaowner(priv); | 402 | priv->owner = nv_rdvgaowner(priv); |
399 | nv_wrvgaowner(priv, 0); | 403 | nv_wrvgaowner(priv, 0); |
400 | 404 | ||
401 | return nouveau_devinit_fini(&priv->base, suspend); | 405 | return 0; |
402 | } | 406 | } |
403 | 407 | ||
404 | int | 408 | int |
@@ -426,9 +430,8 @@ nv04_devinit_dtor(struct nouveau_object *object) | |||
426 | { | 430 | { |
427 | struct nv04_devinit_priv *priv = (void *)object; | 431 | struct nv04_devinit_priv *priv = (void *)object; |
428 | 432 | ||
429 | /* restore vga owner saved at first init, and lock crtc regs */ | 433 | /* restore vga owner saved at first init */ |
430 | nv_wrvgaowner(priv, priv->owner); | 434 | nv_wrvgaowner(priv, priv->owner); |
431 | nv_lockvgac(priv, true); | ||
432 | 435 | ||
433 | nouveau_devinit_destroy(&priv->base); | 436 | nouveau_devinit_destroy(&priv->base); |
434 | } | 437 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h index c4179b6d6eca..822a2fbf44a5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h | |||
@@ -15,8 +15,10 @@ struct nouveau_devinit_impl { | |||
15 | 15 | ||
16 | #define nouveau_devinit_create(p,e,o,d) \ | 16 | #define nouveau_devinit_create(p,e,o,d) \ |
17 | nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d) | 17 | nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d) |
18 | #define nouveau_devinit_destroy(p) \ | 18 | #define nouveau_devinit_destroy(p) ({ \ |
19 | nouveau_subdev_destroy(&(p)->base) | 19 | struct nouveau_devinit *d = (p); \ |
20 | _nouveau_devinit_dtor(nv_object(d)); \ | ||
21 | }) | ||
20 | #define nouveau_devinit_init(p) ({ \ | 22 | #define nouveau_devinit_init(p) ({ \ |
21 | struct nouveau_devinit *d = (p); \ | 23 | struct nouveau_devinit *d = (p); \ |
22 | _nouveau_devinit_init(nv_object(d)); \ | 24 | _nouveau_devinit_init(nv_object(d)); \ |
@@ -28,7 +30,7 @@ struct nouveau_devinit_impl { | |||
28 | 30 | ||
29 | int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *, | 31 | int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *, |
30 | struct nouveau_oclass *, int, void **); | 32 | struct nouveau_oclass *, int, void **); |
31 | #define _nouveau_devinit_dtor _nouveau_subdev_dtor | 33 | void _nouveau_devinit_dtor(struct nouveau_object *); |
32 | int _nouveau_devinit_init(struct nouveau_object *); | 34 | int _nouveau_devinit_init(struct nouveau_object *); |
33 | int _nouveau_devinit_fini(struct nouveau_object *, bool suspend); | 35 | int _nouveau_devinit_fini(struct nouveau_object *, bool suspend); |
34 | 36 | ||