diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_display.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 92 |
1 files changed, 56 insertions, 36 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 612fa6d6a0cb..55c9663ef2bf 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -30,8 +30,22 @@ | |||
30 | #include "nouveau_connector.h" | 30 | #include "nouveau_connector.h" |
31 | #include "nouveau_fb.h" | 31 | #include "nouveau_fb.h" |
32 | #include "nouveau_fbcon.h" | 32 | #include "nouveau_fbcon.h" |
33 | #include "nouveau_ramht.h" | ||
33 | #include "drm_crtc_helper.h" | 34 | #include "drm_crtc_helper.h" |
34 | 35 | ||
36 | static inline int | ||
37 | nv50_sor_nr(struct drm_device *dev) | ||
38 | { | ||
39 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
40 | |||
41 | if (dev_priv->chipset < 0x90 || | ||
42 | dev_priv->chipset == 0x92 || | ||
43 | dev_priv->chipset == 0xa0) | ||
44 | return 2; | ||
45 | |||
46 | return 4; | ||
47 | } | ||
48 | |||
35 | static void | 49 | static void |
36 | nv50_evo_channel_del(struct nouveau_channel **pchan) | 50 | nv50_evo_channel_del(struct nouveau_channel **pchan) |
37 | { | 51 | { |
@@ -42,6 +56,7 @@ nv50_evo_channel_del(struct nouveau_channel **pchan) | |||
42 | *pchan = NULL; | 56 | *pchan = NULL; |
43 | 57 | ||
44 | nouveau_gpuobj_channel_takedown(chan); | 58 | nouveau_gpuobj_channel_takedown(chan); |
59 | nouveau_bo_unmap(chan->pushbuf_bo); | ||
45 | nouveau_bo_ref(NULL, &chan->pushbuf_bo); | 60 | nouveau_bo_ref(NULL, &chan->pushbuf_bo); |
46 | 61 | ||
47 | if (chan->user) | 62 | if (chan->user) |
@@ -65,23 +80,23 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, | |||
65 | return ret; | 80 | return ret; |
66 | obj->engine = NVOBJ_ENGINE_DISPLAY; | 81 | obj->engine = NVOBJ_ENGINE_DISPLAY; |
67 | 82 | ||
68 | ret = nouveau_gpuobj_ref_add(dev, evo, name, obj, NULL); | 83 | nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); |
69 | if (ret) { | 84 | nv_wo32(obj, 4, limit); |
70 | nouveau_gpuobj_del(dev, &obj); | 85 | nv_wo32(obj, 8, offset); |
71 | return ret; | 86 | nv_wo32(obj, 12, 0x00000000); |
72 | } | 87 | nv_wo32(obj, 16, 0x00000000); |
73 | |||
74 | nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); | ||
75 | nv_wo32(dev, obj, 1, limit); | ||
76 | nv_wo32(dev, obj, 2, offset); | ||
77 | nv_wo32(dev, obj, 3, 0x00000000); | ||
78 | nv_wo32(dev, obj, 4, 0x00000000); | ||
79 | if (dev_priv->card_type < NV_C0) | 88 | if (dev_priv->card_type < NV_C0) |
80 | nv_wo32(dev, obj, 5, 0x00010000); | 89 | nv_wo32(obj, 20, 0x00010000); |
81 | else | 90 | else |
82 | nv_wo32(dev, obj, 5, 0x00020000); | 91 | nv_wo32(obj, 20, 0x00020000); |
83 | dev_priv->engine.instmem.flush(dev); | 92 | dev_priv->engine.instmem.flush(dev); |
84 | 93 | ||
94 | ret = nouveau_ramht_insert(evo, name, obj); | ||
95 | nouveau_gpuobj_ref(NULL, &obj); | ||
96 | if (ret) { | ||
97 | return ret; | ||
98 | } | ||
99 | |||
85 | return 0; | 100 | return 0; |
86 | } | 101 | } |
87 | 102 | ||
@@ -89,6 +104,7 @@ static int | |||
89 | nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) | 104 | nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) |
90 | { | 105 | { |
91 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 106 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
107 | struct nouveau_gpuobj *ramht = NULL; | ||
92 | struct nouveau_channel *chan; | 108 | struct nouveau_channel *chan; |
93 | int ret; | 109 | int ret; |
94 | 110 | ||
@@ -102,32 +118,35 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) | |||
102 | chan->user_get = 4; | 118 | chan->user_get = 4; |
103 | chan->user_put = 0; | 119 | chan->user_put = 0; |
104 | 120 | ||
105 | INIT_LIST_HEAD(&chan->ramht_refs); | 121 | ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000, |
106 | 122 | NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin); | |
107 | ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32768, 0x1000, | ||
108 | NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin); | ||
109 | if (ret) { | 123 | if (ret) { |
110 | NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); | 124 | NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); |
111 | nv50_evo_channel_del(pchan); | 125 | nv50_evo_channel_del(pchan); |
112 | return ret; | 126 | return ret; |
113 | } | 127 | } |
114 | 128 | ||
115 | ret = drm_mm_init(&chan->ramin_heap, | 129 | ret = drm_mm_init(&chan->ramin_heap, 0, 32768); |
116 | chan->ramin->gpuobj->im_pramin->start, 32768); | ||
117 | if (ret) { | 130 | if (ret) { |
118 | NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); | 131 | NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); |
119 | nv50_evo_channel_del(pchan); | 132 | nv50_evo_channel_del(pchan); |
120 | return ret; | 133 | return ret; |
121 | } | 134 | } |
122 | 135 | ||
123 | ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 4096, 16, | 136 | ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht); |
124 | 0, &chan->ramht); | ||
125 | if (ret) { | 137 | if (ret) { |
126 | NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); | 138 | NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); |
127 | nv50_evo_channel_del(pchan); | 139 | nv50_evo_channel_del(pchan); |
128 | return ret; | 140 | return ret; |
129 | } | 141 | } |
130 | 142 | ||
143 | ret = nouveau_ramht_new(dev, ramht, &chan->ramht); | ||
144 | nouveau_gpuobj_ref(NULL, &ramht); | ||
145 | if (ret) { | ||
146 | nv50_evo_channel_del(pchan); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
131 | if (dev_priv->chipset != 0x50) { | 150 | if (dev_priv->chipset != 0x50) { |
132 | ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19, | 151 | ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19, |
133 | 0, 0xffffffff); | 152 | 0, 0xffffffff); |
@@ -227,11 +246,11 @@ nv50_display_init(struct drm_device *dev) | |||
227 | nv_wr32(dev, 0x006101d0 + (i * 0x04), val); | 246 | nv_wr32(dev, 0x006101d0 + (i * 0x04), val); |
228 | } | 247 | } |
229 | /* SOR */ | 248 | /* SOR */ |
230 | for (i = 0; i < 4; i++) { | 249 | for (i = 0; i < nv50_sor_nr(dev); i++) { |
231 | val = nv_rd32(dev, 0x0061c000 + (i * 0x800)); | 250 | val = nv_rd32(dev, 0x0061c000 + (i * 0x800)); |
232 | nv_wr32(dev, 0x006101e0 + (i * 0x04), val); | 251 | nv_wr32(dev, 0x006101e0 + (i * 0x04), val); |
233 | } | 252 | } |
234 | /* Something not yet in use, tv-out maybe. */ | 253 | /* EXT */ |
235 | for (i = 0; i < 3; i++) { | 254 | for (i = 0; i < 3; i++) { |
236 | val = nv_rd32(dev, 0x0061e000 + (i * 0x800)); | 255 | val = nv_rd32(dev, 0x0061e000 + (i * 0x800)); |
237 | nv_wr32(dev, 0x006101f0 + (i * 0x04), val); | 256 | nv_wr32(dev, 0x006101f0 + (i * 0x04), val); |
@@ -260,7 +279,7 @@ nv50_display_init(struct drm_device *dev) | |||
260 | if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) { | 279 | if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) { |
261 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100); | 280 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100); |
262 | nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1); | 281 | nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1); |
263 | if (!nv_wait(0x006194e8, 2, 0)) { | 282 | if (!nv_wait(dev, 0x006194e8, 2, 0)) { |
264 | NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n"); | 283 | NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n"); |
265 | NV_ERROR(dev, "0x6194e8 = 0x%08x\n", | 284 | NV_ERROR(dev, "0x6194e8 = 0x%08x\n", |
266 | nv_rd32(dev, 0x6194e8)); | 285 | nv_rd32(dev, 0x6194e8)); |
@@ -291,7 +310,8 @@ nv50_display_init(struct drm_device *dev) | |||
291 | 310 | ||
292 | nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE); | 311 | nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE); |
293 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03); | 312 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03); |
294 | if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x40000000, 0x40000000)) { | 313 | if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), |
314 | 0x40000000, 0x40000000)) { | ||
295 | NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n"); | 315 | NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n"); |
296 | NV_ERROR(dev, "0x610200 = 0x%08x\n", | 316 | NV_ERROR(dev, "0x610200 = 0x%08x\n", |
297 | nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); | 317 | nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); |
@@ -300,7 +320,7 @@ nv50_display_init(struct drm_device *dev) | |||
300 | 320 | ||
301 | for (i = 0; i < 2; i++) { | 321 | for (i = 0; i < 2; i++) { |
302 | nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000); | 322 | nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000); |
303 | if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), | 323 | if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), |
304 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { | 324 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { |
305 | NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); | 325 | NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); |
306 | NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", | 326 | NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", |
@@ -310,7 +330,7 @@ nv50_display_init(struct drm_device *dev) | |||
310 | 330 | ||
311 | nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), | 331 | nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), |
312 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON); | 332 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON); |
313 | if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), | 333 | if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), |
314 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, | 334 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, |
315 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) { | 335 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) { |
316 | NV_ERROR(dev, "timeout: " | 336 | NV_ERROR(dev, "timeout: " |
@@ -321,16 +341,16 @@ nv50_display_init(struct drm_device *dev) | |||
321 | } | 341 | } |
322 | } | 342 | } |
323 | 343 | ||
324 | nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->instance >> 8) | 9); | 344 | nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); |
325 | 345 | ||
326 | /* initialise fifo */ | 346 | /* initialise fifo */ |
327 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0), | 347 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0), |
328 | ((evo->pushbuf_bo->bo.mem.mm_node->start << PAGE_SHIFT) >> 8) | | 348 | ((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) | |
329 | NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM | | 349 | NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM | |
330 | NV50_PDISPLAY_CHANNEL_DMA_CB_VALID); | 350 | NV50_PDISPLAY_CHANNEL_DMA_CB_VALID); |
331 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000); | 351 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000); |
332 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002); | 352 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002); |
333 | if (!nv_wait(0x610200, 0x80000000, 0x00000000)) { | 353 | if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) { |
334 | NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n"); | 354 | NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n"); |
335 | NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200)); | 355 | NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200)); |
336 | return -EBUSY; | 356 | return -EBUSY; |
@@ -370,7 +390,7 @@ nv50_display_init(struct drm_device *dev) | |||
370 | BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1); | 390 | BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1); |
371 | OUT_RING(evo, 0); | 391 | OUT_RING(evo, 0); |
372 | FIRE_RING(evo); | 392 | FIRE_RING(evo); |
373 | if (!nv_wait(0x640004, 0xffffffff, evo->dma.put << 2)) | 393 | if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2)) |
374 | NV_ERROR(dev, "evo pushbuf stalled\n"); | 394 | NV_ERROR(dev, "evo pushbuf stalled\n"); |
375 | 395 | ||
376 | /* enable clock change interrupts. */ | 396 | /* enable clock change interrupts. */ |
@@ -424,7 +444,7 @@ static int nv50_display_disable(struct drm_device *dev) | |||
424 | continue; | 444 | continue; |
425 | 445 | ||
426 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask); | 446 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask); |
427 | if (!nv_wait(NV50_PDISPLAY_INTR_1, mask, mask)) { | 447 | if (!nv_wait(dev, NV50_PDISPLAY_INTR_1, mask, mask)) { |
428 | NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == " | 448 | NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == " |
429 | "0x%08x\n", mask, mask); | 449 | "0x%08x\n", mask, mask); |
430 | NV_ERROR(dev, "0x610024 = 0x%08x\n", | 450 | NV_ERROR(dev, "0x610024 = 0x%08x\n", |
@@ -434,14 +454,14 @@ static int nv50_display_disable(struct drm_device *dev) | |||
434 | 454 | ||
435 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0); | 455 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0); |
436 | nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0); | 456 | nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0); |
437 | if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) { | 457 | if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) { |
438 | NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n"); | 458 | NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n"); |
439 | NV_ERROR(dev, "0x610200 = 0x%08x\n", | 459 | NV_ERROR(dev, "0x610200 = 0x%08x\n", |
440 | nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); | 460 | nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); |
441 | } | 461 | } |
442 | 462 | ||
443 | for (i = 0; i < 3; i++) { | 463 | for (i = 0; i < 3; i++) { |
444 | if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(i), | 464 | if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i), |
445 | NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) { | 465 | NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) { |
446 | NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i); | 466 | NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i); |
447 | NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i, | 467 | NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i, |
@@ -710,7 +730,7 @@ nv50_display_unk10_handler(struct drm_device *dev) | |||
710 | or = i; | 730 | or = i; |
711 | } | 731 | } |
712 | 732 | ||
713 | for (i = 0; type == OUTPUT_ANY && i < 4; i++) { | 733 | for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) { |
714 | if (dev_priv->chipset < 0x90 || | 734 | if (dev_priv->chipset < 0x90 || |
715 | dev_priv->chipset == 0x92 || | 735 | dev_priv->chipset == 0x92 || |
716 | dev_priv->chipset == 0xa0) | 736 | dev_priv->chipset == 0xa0) |
@@ -841,7 +861,7 @@ nv50_display_unk20_handler(struct drm_device *dev) | |||
841 | or = i; | 861 | or = i; |
842 | } | 862 | } |
843 | 863 | ||
844 | for (i = 0; type == OUTPUT_ANY && i < 4; i++) { | 864 | for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) { |
845 | if (dev_priv->chipset < 0x90 || | 865 | if (dev_priv->chipset < 0x90 || |
846 | dev_priv->chipset == 0x92 || | 866 | dev_priv->chipset == 0x92 || |
847 | dev_priv->chipset == 0xa0) | 867 | dev_priv->chipset == 0xa0) |