diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_display.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 1004 |
1 files changed, 1004 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c new file mode 100644 index 000000000000..649db4c1b690 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -0,0 +1,1004 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Maarten Maathuis. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining | ||
6 | * a copy of this software and associated documentation files (the | ||
7 | * "Software"), to deal in the Software without restriction, including | ||
8 | * without limitation the rights to use, copy, modify, merge, publish, | ||
9 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
10 | * permit persons to whom the Software is furnished to do so, subject to | ||
11 | * the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the | ||
14 | * next paragraph) shall be included in all copies or substantial | ||
15 | * portions of the Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
20 | * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE | ||
21 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
22 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
23 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include "nv50_display.h" | ||
28 | #include "nouveau_crtc.h" | ||
29 | #include "nouveau_encoder.h" | ||
30 | #include "nouveau_connector.h" | ||
31 | #include "nouveau_fb.h" | ||
32 | #include "drm_crtc_helper.h" | ||
33 | |||
34 | static void | ||
35 | nv50_evo_channel_del(struct nouveau_channel **pchan) | ||
36 | { | ||
37 | struct nouveau_channel *chan = *pchan; | ||
38 | |||
39 | if (!chan) | ||
40 | return; | ||
41 | *pchan = NULL; | ||
42 | |||
43 | nouveau_gpuobj_channel_takedown(chan); | ||
44 | nouveau_bo_ref(NULL, &chan->pushbuf_bo); | ||
45 | |||
46 | if (chan->user) | ||
47 | iounmap(chan->user); | ||
48 | |||
49 | kfree(chan); | ||
50 | } | ||
51 | |||
52 | static int | ||
53 | nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, | ||
54 | uint32_t tile_flags, uint32_t magic_flags, | ||
55 | uint32_t offset, uint32_t limit) | ||
56 | { | ||
57 | struct drm_nouveau_private *dev_priv = evo->dev->dev_private; | ||
58 | struct drm_device *dev = evo->dev; | ||
59 | struct nouveau_gpuobj *obj = NULL; | ||
60 | int ret; | ||
61 | |||
62 | ret = nouveau_gpuobj_new(dev, evo, 6*4, 32, 0, &obj); | ||
63 | if (ret) | ||
64 | return ret; | ||
65 | obj->engine = NVOBJ_ENGINE_DISPLAY; | ||
66 | |||
67 | ret = nouveau_gpuobj_ref_add(dev, evo, name, obj, NULL); | ||
68 | if (ret) { | ||
69 | nouveau_gpuobj_del(dev, &obj); | ||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | dev_priv->engine.instmem.prepare_access(dev, true); | ||
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 | nv_wo32(dev, obj, 5, 0x00010000); | ||
80 | dev_priv->engine.instmem.finish_access(dev); | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int | ||
86 | nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) | ||
87 | { | ||
88 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
89 | struct nouveau_channel *chan; | ||
90 | int ret; | ||
91 | |||
92 | chan = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL); | ||
93 | if (!chan) | ||
94 | return -ENOMEM; | ||
95 | *pchan = chan; | ||
96 | |||
97 | chan->id = -1; | ||
98 | chan->dev = dev; | ||
99 | chan->user_get = 4; | ||
100 | chan->user_put = 0; | ||
101 | |||
102 | INIT_LIST_HEAD(&chan->ramht_refs); | ||
103 | |||
104 | ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32768, 0x1000, | ||
105 | NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin); | ||
106 | if (ret) { | ||
107 | NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); | ||
108 | nv50_evo_channel_del(pchan); | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | ret = nouveau_mem_init_heap(&chan->ramin_heap, chan->ramin->gpuobj-> | ||
113 | im_pramin->start, 32768); | ||
114 | if (ret) { | ||
115 | NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); | ||
116 | nv50_evo_channel_del(pchan); | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 4096, 16, | ||
121 | 0, &chan->ramht); | ||
122 | if (ret) { | ||
123 | NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); | ||
124 | nv50_evo_channel_del(pchan); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | if (dev_priv->chipset != 0x50) { | ||
129 | ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19, | ||
130 | 0, 0xffffffff); | ||
131 | if (ret) { | ||
132 | nv50_evo_channel_del(pchan); | ||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | |||
137 | ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB32, 0x7a, 0x19, | ||
138 | 0, 0xffffffff); | ||
139 | if (ret) { | ||
140 | nv50_evo_channel_del(pchan); | ||
141 | return ret; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoVRAM, 0, 0x19, | ||
146 | 0, dev_priv->vram_size); | ||
147 | if (ret) { | ||
148 | nv50_evo_channel_del(pchan); | ||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, | ||
153 | false, true, &chan->pushbuf_bo); | ||
154 | if (ret == 0) | ||
155 | ret = nouveau_bo_pin(chan->pushbuf_bo, TTM_PL_FLAG_VRAM); | ||
156 | if (ret) { | ||
157 | NV_ERROR(dev, "Error creating EVO DMA push buffer: %d\n", ret); | ||
158 | nv50_evo_channel_del(pchan); | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | ret = nouveau_bo_map(chan->pushbuf_bo); | ||
163 | if (ret) { | ||
164 | NV_ERROR(dev, "Error mapping EVO DMA push buffer: %d\n", ret); | ||
165 | nv50_evo_channel_del(pchan); | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | chan->user = ioremap(pci_resource_start(dev->pdev, 0) + | ||
170 | NV50_PDISPLAY_USER(0), PAGE_SIZE); | ||
171 | if (!chan->user) { | ||
172 | NV_ERROR(dev, "Error mapping EVO control regs.\n"); | ||
173 | nv50_evo_channel_del(pchan); | ||
174 | return -ENOMEM; | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | int | ||
181 | nv50_display_init(struct drm_device *dev) | ||
182 | { | ||
183 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
184 | struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; | ||
185 | struct nouveau_channel *evo = dev_priv->evo; | ||
186 | struct drm_connector *connector; | ||
187 | uint32_t val, ram_amount, hpd_en[2]; | ||
188 | uint64_t start; | ||
189 | int ret, i; | ||
190 | |||
191 | NV_DEBUG_KMS(dev, "\n"); | ||
192 | |||
193 | nv_wr32(dev, 0x00610184, nv_rd32(dev, 0x00614004)); | ||
194 | /* | ||
195 | * I think the 0x006101XX range is some kind of main control area | ||
196 | * that enables things. | ||
197 | */ | ||
198 | /* CRTC? */ | ||
199 | for (i = 0; i < 2; i++) { | ||
200 | val = nv_rd32(dev, 0x00616100 + (i * 0x800)); | ||
201 | nv_wr32(dev, 0x00610190 + (i * 0x10), val); | ||
202 | val = nv_rd32(dev, 0x00616104 + (i * 0x800)); | ||
203 | nv_wr32(dev, 0x00610194 + (i * 0x10), val); | ||
204 | val = nv_rd32(dev, 0x00616108 + (i * 0x800)); | ||
205 | nv_wr32(dev, 0x00610198 + (i * 0x10), val); | ||
206 | val = nv_rd32(dev, 0x0061610c + (i * 0x800)); | ||
207 | nv_wr32(dev, 0x0061019c + (i * 0x10), val); | ||
208 | } | ||
209 | /* DAC */ | ||
210 | for (i = 0; i < 3; i++) { | ||
211 | val = nv_rd32(dev, 0x0061a000 + (i * 0x800)); | ||
212 | nv_wr32(dev, 0x006101d0 + (i * 0x04), val); | ||
213 | } | ||
214 | /* SOR */ | ||
215 | for (i = 0; i < 4; i++) { | ||
216 | val = nv_rd32(dev, 0x0061c000 + (i * 0x800)); | ||
217 | nv_wr32(dev, 0x006101e0 + (i * 0x04), val); | ||
218 | } | ||
219 | /* Something not yet in use, tv-out maybe. */ | ||
220 | for (i = 0; i < 3; i++) { | ||
221 | val = nv_rd32(dev, 0x0061e000 + (i * 0x800)); | ||
222 | nv_wr32(dev, 0x006101f0 + (i * 0x04), val); | ||
223 | } | ||
224 | |||
225 | for (i = 0; i < 3; i++) { | ||
226 | nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(i), 0x00550000 | | ||
227 | NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING); | ||
228 | nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(i), 0x00000001); | ||
229 | } | ||
230 | |||
231 | /* This used to be in crtc unblank, but seems out of place there. */ | ||
232 | nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0); | ||
233 | /* RAM is clamped to 256 MiB. */ | ||
234 | ram_amount = dev_priv->vram_size; | ||
235 | NV_DEBUG_KMS(dev, "ram_amount %d\n", ram_amount); | ||
236 | if (ram_amount > 256*1024*1024) | ||
237 | ram_amount = 256*1024*1024; | ||
238 | nv_wr32(dev, NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1); | ||
239 | nv_wr32(dev, NV50_PDISPLAY_UNK_388, 0x150000); | ||
240 | nv_wr32(dev, NV50_PDISPLAY_UNK_38C, 0); | ||
241 | |||
242 | /* The precise purpose is unknown, i suspect it has something to do | ||
243 | * with text mode. | ||
244 | */ | ||
245 | if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) { | ||
246 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100); | ||
247 | nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1); | ||
248 | if (!nv_wait(0x006194e8, 2, 0)) { | ||
249 | NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n"); | ||
250 | NV_ERROR(dev, "0x6194e8 = 0x%08x\n", | ||
251 | nv_rd32(dev, 0x6194e8)); | ||
252 | return -EBUSY; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | /* taken from nv bug #12637, attempts to un-wedge the hw if it's | ||
257 | * stuck in some unspecified state | ||
258 | */ | ||
259 | start = ptimer->read(dev); | ||
260 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x2b00); | ||
261 | while ((val = nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))) & 0x1e0000) { | ||
262 | if ((val & 0x9f0000) == 0x20000) | ||
263 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), | ||
264 | val | 0x800000); | ||
265 | |||
266 | if ((val & 0x3f0000) == 0x30000) | ||
267 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), | ||
268 | val | 0x200000); | ||
269 | |||
270 | if (ptimer->read(dev) - start > 1000000000ULL) { | ||
271 | NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) != 0\n"); | ||
272 | NV_ERROR(dev, "0x610200 = 0x%08x\n", val); | ||
273 | return -EBUSY; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE); | ||
278 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03); | ||
279 | if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x40000000, 0x40000000)) { | ||
280 | NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n"); | ||
281 | NV_ERROR(dev, "0x610200 = 0x%08x\n", | ||
282 | nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); | ||
283 | return -EBUSY; | ||
284 | } | ||
285 | |||
286 | for (i = 0; i < 2; i++) { | ||
287 | nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000); | ||
288 | if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), | ||
289 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { | ||
290 | NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); | ||
291 | NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", | ||
292 | nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i))); | ||
293 | return -EBUSY; | ||
294 | } | ||
295 | |||
296 | nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), | ||
297 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON); | ||
298 | if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), | ||
299 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, | ||
300 | NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) { | ||
301 | NV_ERROR(dev, "timeout: " | ||
302 | "CURSOR_CTRL2_STATUS_ACTIVE(%d)\n", i); | ||
303 | NV_ERROR(dev, "CURSOR_CTRL2(%d) = 0x%08x\n", i, | ||
304 | nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i))); | ||
305 | return -EBUSY; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->instance >> 8) | 9); | ||
310 | |||
311 | /* initialise fifo */ | ||
312 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0), | ||
313 | ((evo->pushbuf_bo->bo.mem.mm_node->start << PAGE_SHIFT) >> 8) | | ||
314 | NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM | | ||
315 | NV50_PDISPLAY_CHANNEL_DMA_CB_VALID); | ||
316 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000); | ||
317 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002); | ||
318 | if (!nv_wait(0x610200, 0x80000000, 0x00000000)) { | ||
319 | NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n"); | ||
320 | NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200)); | ||
321 | return -EBUSY; | ||
322 | } | ||
323 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), | ||
324 | (nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)) & ~0x00000003) | | ||
325 | NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED); | ||
326 | nv_wr32(dev, NV50_PDISPLAY_USER_PUT(0), 0); | ||
327 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x01000003 | | ||
328 | NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED); | ||
329 | nv_wr32(dev, 0x610300, nv_rd32(dev, 0x610300) & ~1); | ||
330 | |||
331 | evo->dma.max = (4096/4) - 2; | ||
332 | evo->dma.put = 0; | ||
333 | evo->dma.cur = evo->dma.put; | ||
334 | evo->dma.free = evo->dma.max - evo->dma.cur; | ||
335 | |||
336 | ret = RING_SPACE(evo, NOUVEAU_DMA_SKIPS); | ||
337 | if (ret) | ||
338 | return ret; | ||
339 | |||
340 | for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) | ||
341 | OUT_RING(evo, 0); | ||
342 | |||
343 | ret = RING_SPACE(evo, 11); | ||
344 | if (ret) | ||
345 | return ret; | ||
346 | BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2); | ||
347 | OUT_RING(evo, NV50_EVO_UNK84_NOTIFY_DISABLED); | ||
348 | OUT_RING(evo, NV50_EVO_DMA_NOTIFY_HANDLE_NONE); | ||
349 | BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, FB_DMA), 1); | ||
350 | OUT_RING(evo, NV50_EVO_CRTC_FB_DMA_HANDLE_NONE); | ||
351 | BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK0800), 1); | ||
352 | OUT_RING(evo, 0); | ||
353 | BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, DISPLAY_START), 1); | ||
354 | OUT_RING(evo, 0); | ||
355 | BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1); | ||
356 | OUT_RING(evo, 0); | ||
357 | FIRE_RING(evo); | ||
358 | if (!nv_wait(0x640004, 0xffffffff, evo->dma.put << 2)) | ||
359 | NV_ERROR(dev, "evo pushbuf stalled\n"); | ||
360 | |||
361 | /* enable clock change interrupts. */ | ||
362 | nv_wr32(dev, 0x610028, 0x00010001); | ||
363 | nv_wr32(dev, NV50_PDISPLAY_INTR_EN, (NV50_PDISPLAY_INTR_EN_CLK_UNK10 | | ||
364 | NV50_PDISPLAY_INTR_EN_CLK_UNK20 | | ||
365 | NV50_PDISPLAY_INTR_EN_CLK_UNK40)); | ||
366 | |||
367 | /* enable hotplug interrupts */ | ||
368 | hpd_en[0] = hpd_en[1] = 0; | ||
369 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
370 | struct nouveau_connector *conn = nouveau_connector(connector); | ||
371 | struct dcb_gpio_entry *gpio; | ||
372 | |||
373 | if (conn->dcb->gpio_tag == 0xff) | ||
374 | continue; | ||
375 | |||
376 | gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag); | ||
377 | if (!gpio) | ||
378 | continue; | ||
379 | |||
380 | hpd_en[gpio->line >> 4] |= (0x00010001 << (gpio->line & 0xf)); | ||
381 | } | ||
382 | |||
383 | nv_wr32(dev, 0xe054, 0xffffffff); | ||
384 | nv_wr32(dev, 0xe050, hpd_en[0]); | ||
385 | if (dev_priv->chipset >= 0x90) { | ||
386 | nv_wr32(dev, 0xe074, 0xffffffff); | ||
387 | nv_wr32(dev, 0xe070, hpd_en[1]); | ||
388 | } | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int nv50_display_disable(struct drm_device *dev) | ||
394 | { | ||
395 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
396 | struct drm_crtc *drm_crtc; | ||
397 | int ret, i; | ||
398 | |||
399 | NV_DEBUG_KMS(dev, "\n"); | ||
400 | |||
401 | list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { | ||
402 | struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc); | ||
403 | |||
404 | nv50_crtc_blank(crtc, true); | ||
405 | } | ||
406 | |||
407 | ret = RING_SPACE(dev_priv->evo, 2); | ||
408 | if (ret == 0) { | ||
409 | BEGIN_RING(dev_priv->evo, 0, NV50_EVO_UPDATE, 1); | ||
410 | OUT_RING(dev_priv->evo, 0); | ||
411 | } | ||
412 | FIRE_RING(dev_priv->evo); | ||
413 | |||
414 | /* Almost like ack'ing a vblank interrupt, maybe in the spirit of | ||
415 | * cleaning up? | ||
416 | */ | ||
417 | list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { | ||
418 | struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc); | ||
419 | uint32_t mask = NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(crtc->index); | ||
420 | |||
421 | if (!crtc->base.enabled) | ||
422 | continue; | ||
423 | |||
424 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask); | ||
425 | if (!nv_wait(NV50_PDISPLAY_INTR_1, mask, mask)) { | ||
426 | NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == " | ||
427 | "0x%08x\n", mask, mask); | ||
428 | NV_ERROR(dev, "0x610024 = 0x%08x\n", | ||
429 | nv_rd32(dev, NV50_PDISPLAY_INTR_1)); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0); | ||
434 | nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0); | ||
435 | if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) { | ||
436 | NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n"); | ||
437 | NV_ERROR(dev, "0x610200 = 0x%08x\n", | ||
438 | nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); | ||
439 | } | ||
440 | |||
441 | for (i = 0; i < 3; i++) { | ||
442 | if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(i), | ||
443 | NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) { | ||
444 | NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i); | ||
445 | NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i, | ||
446 | nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i))); | ||
447 | } | ||
448 | } | ||
449 | |||
450 | /* disable interrupts. */ | ||
451 | nv_wr32(dev, NV50_PDISPLAY_INTR_EN, 0x00000000); | ||
452 | |||
453 | /* disable hotplug interrupts */ | ||
454 | nv_wr32(dev, 0xe054, 0xffffffff); | ||
455 | nv_wr32(dev, 0xe050, 0x00000000); | ||
456 | if (dev_priv->chipset >= 0x90) { | ||
457 | nv_wr32(dev, 0xe074, 0xffffffff); | ||
458 | nv_wr32(dev, 0xe070, 0x00000000); | ||
459 | } | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | int nv50_display_create(struct drm_device *dev) | ||
464 | { | ||
465 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
466 | struct dcb_table *dcb = &dev_priv->vbios.dcb; | ||
467 | int ret, i; | ||
468 | |||
469 | NV_DEBUG_KMS(dev, "\n"); | ||
470 | |||
471 | /* init basic kernel modesetting */ | ||
472 | drm_mode_config_init(dev); | ||
473 | |||
474 | /* Initialise some optional connector properties. */ | ||
475 | drm_mode_create_scaling_mode_property(dev); | ||
476 | drm_mode_create_dithering_property(dev); | ||
477 | |||
478 | dev->mode_config.min_width = 0; | ||
479 | dev->mode_config.min_height = 0; | ||
480 | |||
481 | dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; | ||
482 | |||
483 | dev->mode_config.max_width = 8192; | ||
484 | dev->mode_config.max_height = 8192; | ||
485 | |||
486 | dev->mode_config.fb_base = dev_priv->fb_phys; | ||
487 | |||
488 | /* Create EVO channel */ | ||
489 | ret = nv50_evo_channel_new(dev, &dev_priv->evo); | ||
490 | if (ret) { | ||
491 | NV_ERROR(dev, "Error creating EVO channel: %d\n", ret); | ||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | /* Create CRTC objects */ | ||
496 | for (i = 0; i < 2; i++) | ||
497 | nv50_crtc_create(dev, i); | ||
498 | |||
499 | /* We setup the encoders from the BIOS table */ | ||
500 | for (i = 0 ; i < dcb->entries; i++) { | ||
501 | struct dcb_entry *entry = &dcb->entry[i]; | ||
502 | |||
503 | if (entry->location != DCB_LOC_ON_CHIP) { | ||
504 | NV_WARN(dev, "Off-chip encoder %d/%d unsupported\n", | ||
505 | entry->type, ffs(entry->or) - 1); | ||
506 | continue; | ||
507 | } | ||
508 | |||
509 | switch (entry->type) { | ||
510 | case OUTPUT_TMDS: | ||
511 | case OUTPUT_LVDS: | ||
512 | case OUTPUT_DP: | ||
513 | nv50_sor_create(dev, entry); | ||
514 | break; | ||
515 | case OUTPUT_ANALOG: | ||
516 | nv50_dac_create(dev, entry); | ||
517 | break; | ||
518 | default: | ||
519 | NV_WARN(dev, "DCB encoder %d unknown\n", entry->type); | ||
520 | continue; | ||
521 | } | ||
522 | } | ||
523 | |||
524 | for (i = 0 ; i < dcb->connector.entries; i++) { | ||
525 | if (i != 0 && dcb->connector.entry[i].index2 == | ||
526 | dcb->connector.entry[i - 1].index2) | ||
527 | continue; | ||
528 | nouveau_connector_create(dev, &dcb->connector.entry[i]); | ||
529 | } | ||
530 | |||
531 | ret = nv50_display_init(dev); | ||
532 | if (ret) { | ||
533 | nv50_display_destroy(dev); | ||
534 | return ret; | ||
535 | } | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | int nv50_display_destroy(struct drm_device *dev) | ||
541 | { | ||
542 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
543 | |||
544 | NV_DEBUG_KMS(dev, "\n"); | ||
545 | |||
546 | drm_mode_config_cleanup(dev); | ||
547 | |||
548 | nv50_display_disable(dev); | ||
549 | nv50_evo_channel_del(&dev_priv->evo); | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | static inline uint32_t | ||
555 | nv50_display_mode_ctrl(struct drm_device *dev, bool sor, int or) | ||
556 | { | ||
557 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
558 | uint32_t mc; | ||
559 | |||
560 | if (sor) { | ||
561 | if (dev_priv->chipset < 0x90 || | ||
562 | dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0) | ||
563 | mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(or)); | ||
564 | else | ||
565 | mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(or)); | ||
566 | } else { | ||
567 | mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(or)); | ||
568 | } | ||
569 | |||
570 | return mc; | ||
571 | } | ||
572 | |||
573 | static int | ||
574 | nv50_display_irq_head(struct drm_device *dev, int *phead, | ||
575 | struct dcb_entry **pdcbent) | ||
576 | { | ||
577 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
578 | uint32_t unk30 = nv_rd32(dev, NV50_PDISPLAY_UNK30_CTRL); | ||
579 | uint32_t dac = 0, sor = 0; | ||
580 | int head, i, or = 0, type = OUTPUT_ANY; | ||
581 | |||
582 | /* We're assuming that head 0 *or* head 1 will be active here, | ||
583 | * and not both. I'm not sure if the hw will even signal both | ||
584 | * ever, but it definitely shouldn't for us as we commit each | ||
585 | * CRTC separately, and submission will be blocked by the GPU | ||
586 | * until we handle each in turn. | ||
587 | */ | ||
588 | NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); | ||
589 | head = ffs((unk30 >> 9) & 3) - 1; | ||
590 | if (head < 0) | ||
591 | return -EINVAL; | ||
592 | |||
593 | /* This assumes CRTCs are never bound to multiple encoders, which | ||
594 | * should be the case. | ||
595 | */ | ||
596 | for (i = 0; i < 3 && type == OUTPUT_ANY; i++) { | ||
597 | uint32_t mc = nv50_display_mode_ctrl(dev, false, i); | ||
598 | if (!(mc & (1 << head))) | ||
599 | continue; | ||
600 | |||
601 | switch ((mc >> 8) & 0xf) { | ||
602 | case 0: type = OUTPUT_ANALOG; break; | ||
603 | case 1: type = OUTPUT_TV; break; | ||
604 | default: | ||
605 | NV_ERROR(dev, "unknown dac mode_ctrl: 0x%08x\n", dac); | ||
606 | return -1; | ||
607 | } | ||
608 | |||
609 | or = i; | ||
610 | } | ||
611 | |||
612 | for (i = 0; i < 4 && type == OUTPUT_ANY; i++) { | ||
613 | uint32_t mc = nv50_display_mode_ctrl(dev, true, i); | ||
614 | if (!(mc & (1 << head))) | ||
615 | continue; | ||
616 | |||
617 | switch ((mc >> 8) & 0xf) { | ||
618 | case 0: type = OUTPUT_LVDS; break; | ||
619 | case 1: type = OUTPUT_TMDS; break; | ||
620 | case 2: type = OUTPUT_TMDS; break; | ||
621 | case 5: type = OUTPUT_TMDS; break; | ||
622 | case 8: type = OUTPUT_DP; break; | ||
623 | case 9: type = OUTPUT_DP; break; | ||
624 | default: | ||
625 | NV_ERROR(dev, "unknown sor mode_ctrl: 0x%08x\n", sor); | ||
626 | return -1; | ||
627 | } | ||
628 | |||
629 | or = i; | ||
630 | } | ||
631 | |||
632 | NV_DEBUG_KMS(dev, "type %d, or %d\n", type, or); | ||
633 | if (type == OUTPUT_ANY) { | ||
634 | NV_ERROR(dev, "unknown encoder!!\n"); | ||
635 | return -1; | ||
636 | } | ||
637 | |||
638 | for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { | ||
639 | struct dcb_entry *dcbent = &dev_priv->vbios.dcb.entry[i]; | ||
640 | |||
641 | if (dcbent->type != type) | ||
642 | continue; | ||
643 | |||
644 | if (!(dcbent->or & (1 << or))) | ||
645 | continue; | ||
646 | |||
647 | *phead = head; | ||
648 | *pdcbent = dcbent; | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or); | ||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | static uint32_t | ||
657 | nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent, | ||
658 | int pxclk) | ||
659 | { | ||
660 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
661 | struct nouveau_connector *nv_connector = NULL; | ||
662 | struct drm_encoder *encoder; | ||
663 | struct nvbios *bios = &dev_priv->vbios; | ||
664 | uint32_t mc, script = 0, or; | ||
665 | |||
666 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
667 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
668 | |||
669 | if (nv_encoder->dcb != dcbent) | ||
670 | continue; | ||
671 | |||
672 | nv_connector = nouveau_encoder_connector_get(nv_encoder); | ||
673 | break; | ||
674 | } | ||
675 | |||
676 | or = ffs(dcbent->or) - 1; | ||
677 | mc = nv50_display_mode_ctrl(dev, dcbent->type != OUTPUT_ANALOG, or); | ||
678 | switch (dcbent->type) { | ||
679 | case OUTPUT_LVDS: | ||
680 | script = (mc >> 8) & 0xf; | ||
681 | if (bios->fp_no_ddc) { | ||
682 | if (bios->fp.dual_link) | ||
683 | script |= 0x0100; | ||
684 | if (bios->fp.if_is_24bit) | ||
685 | script |= 0x0200; | ||
686 | } else { | ||
687 | if (pxclk >= bios->fp.duallink_transition_clk) { | ||
688 | script |= 0x0100; | ||
689 | if (bios->fp.strapless_is_24bit & 2) | ||
690 | script |= 0x0200; | ||
691 | } else | ||
692 | if (bios->fp.strapless_is_24bit & 1) | ||
693 | script |= 0x0200; | ||
694 | |||
695 | if (nv_connector && nv_connector->edid && | ||
696 | (nv_connector->edid->revision >= 4) && | ||
697 | (nv_connector->edid->input & 0x70) >= 0x20) | ||
698 | script |= 0x0200; | ||
699 | } | ||
700 | |||
701 | if (nouveau_uscript_lvds >= 0) { | ||
702 | NV_INFO(dev, "override script 0x%04x with 0x%04x " | ||
703 | "for output LVDS-%d\n", script, | ||
704 | nouveau_uscript_lvds, or); | ||
705 | script = nouveau_uscript_lvds; | ||
706 | } | ||
707 | break; | ||
708 | case OUTPUT_TMDS: | ||
709 | script = (mc >> 8) & 0xf; | ||
710 | if (pxclk >= 165000) | ||
711 | script |= 0x0100; | ||
712 | |||
713 | if (nouveau_uscript_tmds >= 0) { | ||
714 | NV_INFO(dev, "override script 0x%04x with 0x%04x " | ||
715 | "for output TMDS-%d\n", script, | ||
716 | nouveau_uscript_tmds, or); | ||
717 | script = nouveau_uscript_tmds; | ||
718 | } | ||
719 | break; | ||
720 | case OUTPUT_DP: | ||
721 | script = (mc >> 8) & 0xf; | ||
722 | break; | ||
723 | case OUTPUT_ANALOG: | ||
724 | script = 0xff; | ||
725 | break; | ||
726 | default: | ||
727 | NV_ERROR(dev, "modeset on unsupported output type!\n"); | ||
728 | break; | ||
729 | } | ||
730 | |||
731 | return script; | ||
732 | } | ||
733 | |||
734 | static void | ||
735 | nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc) | ||
736 | { | ||
737 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
738 | struct nouveau_channel *chan; | ||
739 | struct list_head *entry, *tmp; | ||
740 | |||
741 | list_for_each_safe(entry, tmp, &dev_priv->vbl_waiting) { | ||
742 | chan = list_entry(entry, struct nouveau_channel, nvsw.vbl_wait); | ||
743 | |||
744 | nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset, | ||
745 | chan->nvsw.vblsem_rval); | ||
746 | list_del(&chan->nvsw.vbl_wait); | ||
747 | } | ||
748 | } | ||
749 | |||
750 | static void | ||
751 | nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) | ||
752 | { | ||
753 | intr &= NV50_PDISPLAY_INTR_1_VBLANK_CRTC; | ||
754 | |||
755 | if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0) | ||
756 | nv50_display_vblank_crtc_handler(dev, 0); | ||
757 | |||
758 | if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1) | ||
759 | nv50_display_vblank_crtc_handler(dev, 1); | ||
760 | |||
761 | nv_wr32(dev, NV50_PDISPLAY_INTR_EN, nv_rd32(dev, | ||
762 | NV50_PDISPLAY_INTR_EN) & ~intr); | ||
763 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr); | ||
764 | } | ||
765 | |||
766 | static void | ||
767 | nv50_display_unk10_handler(struct drm_device *dev) | ||
768 | { | ||
769 | struct dcb_entry *dcbent; | ||
770 | int head, ret; | ||
771 | |||
772 | ret = nv50_display_irq_head(dev, &head, &dcbent); | ||
773 | if (ret) | ||
774 | goto ack; | ||
775 | |||
776 | nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8); | ||
777 | |||
778 | nouveau_bios_run_display_table(dev, dcbent, 0, -1); | ||
779 | |||
780 | ack: | ||
781 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10); | ||
782 | nv_wr32(dev, 0x610030, 0x80000000); | ||
783 | } | ||
784 | |||
785 | static void | ||
786 | nv50_display_unk20_handler(struct drm_device *dev) | ||
787 | { | ||
788 | struct dcb_entry *dcbent; | ||
789 | uint32_t tmp, pclk, script; | ||
790 | int head, or, ret; | ||
791 | |||
792 | ret = nv50_display_irq_head(dev, &head, &dcbent); | ||
793 | if (ret) | ||
794 | goto ack; | ||
795 | or = ffs(dcbent->or) - 1; | ||
796 | pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff; | ||
797 | script = nv50_display_script_select(dev, dcbent, pclk); | ||
798 | |||
799 | NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk); | ||
800 | |||
801 | if (dcbent->type != OUTPUT_DP) | ||
802 | nouveau_bios_run_display_table(dev, dcbent, 0, -2); | ||
803 | |||
804 | nv50_crtc_set_clock(dev, head, pclk); | ||
805 | |||
806 | nouveau_bios_run_display_table(dev, dcbent, script, pclk); | ||
807 | |||
808 | tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head)); | ||
809 | tmp &= ~0x000000f; | ||
810 | nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp); | ||
811 | |||
812 | if (dcbent->type != OUTPUT_ANALOG) { | ||
813 | tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); | ||
814 | tmp &= ~0x00000f0f; | ||
815 | if (script & 0x0100) | ||
816 | tmp |= 0x00000101; | ||
817 | nv_wr32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or), tmp); | ||
818 | } else { | ||
819 | nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0); | ||
820 | } | ||
821 | |||
822 | ack: | ||
823 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20); | ||
824 | nv_wr32(dev, 0x610030, 0x80000000); | ||
825 | } | ||
826 | |||
827 | static void | ||
828 | nv50_display_unk40_handler(struct drm_device *dev) | ||
829 | { | ||
830 | struct dcb_entry *dcbent; | ||
831 | int head, pclk, script, ret; | ||
832 | |||
833 | ret = nv50_display_irq_head(dev, &head, &dcbent); | ||
834 | if (ret) | ||
835 | goto ack; | ||
836 | pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff; | ||
837 | script = nv50_display_script_select(dev, dcbent, pclk); | ||
838 | |||
839 | nouveau_bios_run_display_table(dev, dcbent, script, -pclk); | ||
840 | |||
841 | ack: | ||
842 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40); | ||
843 | nv_wr32(dev, 0x610030, 0x80000000); | ||
844 | nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) | 8); | ||
845 | } | ||
846 | |||
847 | void | ||
848 | nv50_display_irq_handler_bh(struct work_struct *work) | ||
849 | { | ||
850 | struct drm_nouveau_private *dev_priv = | ||
851 | container_of(work, struct drm_nouveau_private, irq_work); | ||
852 | struct drm_device *dev = dev_priv->dev; | ||
853 | |||
854 | for (;;) { | ||
855 | uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0); | ||
856 | uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1); | ||
857 | |||
858 | NV_DEBUG_KMS(dev, "PDISPLAY_INTR_BH 0x%08x 0x%08x\n", intr0, intr1); | ||
859 | |||
860 | if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK10) | ||
861 | nv50_display_unk10_handler(dev); | ||
862 | else | ||
863 | if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK20) | ||
864 | nv50_display_unk20_handler(dev); | ||
865 | else | ||
866 | if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK40) | ||
867 | nv50_display_unk40_handler(dev); | ||
868 | else | ||
869 | break; | ||
870 | } | ||
871 | |||
872 | nv_wr32(dev, NV03_PMC_INTR_EN_0, 1); | ||
873 | } | ||
874 | |||
875 | static void | ||
876 | nv50_display_error_handler(struct drm_device *dev) | ||
877 | { | ||
878 | uint32_t addr, data; | ||
879 | |||
880 | nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000); | ||
881 | addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR); | ||
882 | data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA); | ||
883 | |||
884 | NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x (0x%04x 0x%02x)\n", | ||
885 | 0, addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf); | ||
886 | |||
887 | nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR, 0x90000000); | ||
888 | } | ||
889 | |||
890 | void | ||
891 | nv50_display_irq_hotplug_bh(struct work_struct *work) | ||
892 | { | ||
893 | struct drm_nouveau_private *dev_priv = | ||
894 | container_of(work, struct drm_nouveau_private, hpd_work); | ||
895 | struct drm_device *dev = dev_priv->dev; | ||
896 | struct drm_connector *connector; | ||
897 | const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; | ||
898 | uint32_t unplug_mask, plug_mask, change_mask; | ||
899 | uint32_t hpd0, hpd1 = 0; | ||
900 | |||
901 | hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050); | ||
902 | if (dev_priv->chipset >= 0x90) | ||
903 | hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070); | ||
904 | |||
905 | plug_mask = (hpd0 & 0x0000ffff) | (hpd1 << 16); | ||
906 | unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000); | ||
907 | change_mask = plug_mask | unplug_mask; | ||
908 | |||
909 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
910 | struct drm_encoder_helper_funcs *helper; | ||
911 | struct nouveau_connector *nv_connector = | ||
912 | nouveau_connector(connector); | ||
913 | struct nouveau_encoder *nv_encoder; | ||
914 | struct dcb_gpio_entry *gpio; | ||
915 | uint32_t reg; | ||
916 | bool plugged; | ||
917 | |||
918 | if (!nv_connector->dcb) | ||
919 | continue; | ||
920 | |||
921 | gpio = nouveau_bios_gpio_entry(dev, nv_connector->dcb->gpio_tag); | ||
922 | if (!gpio || !(change_mask & (1 << gpio->line))) | ||
923 | continue; | ||
924 | |||
925 | reg = nv_rd32(dev, gpio_reg[gpio->line >> 3]); | ||
926 | plugged = !!(reg & (4 << ((gpio->line & 7) << 2))); | ||
927 | NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un", | ||
928 | drm_get_connector_name(connector)) ; | ||
929 | |||
930 | if (!connector->encoder || !connector->encoder->crtc || | ||
931 | !connector->encoder->crtc->enabled) | ||
932 | continue; | ||
933 | nv_encoder = nouveau_encoder(connector->encoder); | ||
934 | helper = connector->encoder->helper_private; | ||
935 | |||
936 | if (nv_encoder->dcb->type != OUTPUT_DP) | ||
937 | continue; | ||
938 | |||
939 | if (plugged) | ||
940 | helper->dpms(connector->encoder, DRM_MODE_DPMS_ON); | ||
941 | else | ||
942 | helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); | ||
943 | } | ||
944 | |||
945 | nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054)); | ||
946 | if (dev_priv->chipset >= 0x90) | ||
947 | nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); | ||
948 | } | ||
949 | |||
950 | void | ||
951 | nv50_display_irq_handler(struct drm_device *dev) | ||
952 | { | ||
953 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
954 | uint32_t delayed = 0; | ||
955 | |||
956 | if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) { | ||
957 | if (!work_pending(&dev_priv->hpd_work)) | ||
958 | queue_work(dev_priv->wq, &dev_priv->hpd_work); | ||
959 | } | ||
960 | |||
961 | while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) { | ||
962 | uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0); | ||
963 | uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1); | ||
964 | uint32_t clock; | ||
965 | |||
966 | NV_DEBUG_KMS(dev, "PDISPLAY_INTR 0x%08x 0x%08x\n", intr0, intr1); | ||
967 | |||
968 | if (!intr0 && !(intr1 & ~delayed)) | ||
969 | break; | ||
970 | |||
971 | if (intr0 & 0x00010000) { | ||
972 | nv50_display_error_handler(dev); | ||
973 | intr0 &= ~0x00010000; | ||
974 | } | ||
975 | |||
976 | if (intr1 & NV50_PDISPLAY_INTR_1_VBLANK_CRTC) { | ||
977 | nv50_display_vblank_handler(dev, intr1); | ||
978 | intr1 &= ~NV50_PDISPLAY_INTR_1_VBLANK_CRTC; | ||
979 | } | ||
980 | |||
981 | clock = (intr1 & (NV50_PDISPLAY_INTR_1_CLK_UNK10 | | ||
982 | NV50_PDISPLAY_INTR_1_CLK_UNK20 | | ||
983 | NV50_PDISPLAY_INTR_1_CLK_UNK40)); | ||
984 | if (clock) { | ||
985 | nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); | ||
986 | if (!work_pending(&dev_priv->irq_work)) | ||
987 | queue_work(dev_priv->wq, &dev_priv->irq_work); | ||
988 | delayed |= clock; | ||
989 | intr1 &= ~clock; | ||
990 | } | ||
991 | |||
992 | if (intr0) { | ||
993 | NV_ERROR(dev, "unknown PDISPLAY_INTR_0: 0x%08x\n", intr0); | ||
994 | nv_wr32(dev, NV50_PDISPLAY_INTR_0, intr0); | ||
995 | } | ||
996 | |||
997 | if (intr1) { | ||
998 | NV_ERROR(dev, | ||
999 | "unknown PDISPLAY_INTR_1: 0x%08x\n", intr1); | ||
1000 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr1); | ||
1001 | } | ||
1002 | } | ||
1003 | } | ||
1004 | |||