blob: 636d3a204f0a735334d41d15432fe7e887024fcc [file] [log] [blame]
Ben Skeggs6ee73862009-12-11 19:24:15 +10001/*
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"
Dave Airlie4abe3522010-03-30 05:34:18 +000032#include "nouveau_fbcon.h"
Ben Skeggsa8eaebc2010-09-01 15:24:31 +100033#include "nouveau_ramht.h"
Ben Skeggs6ee73862009-12-11 19:24:15 +100034#include "drm_crtc_helper.h"
35
Ben Skeggs19b7fc72010-11-03 10:27:27 +100036static void nv50_display_isr(struct drm_device *);
37
Ben Skeggs8597a1b2010-09-06 11:39:25 +100038static inline int
39nv50_sor_nr(struct drm_device *dev)
40{
41 struct drm_nouveau_private *dev_priv = dev->dev_private;
42
43 if (dev_priv->chipset < 0x90 ||
44 dev_priv->chipset == 0x92 ||
45 dev_priv->chipset == 0xa0)
46 return 2;
47
48 return 4;
49}
50
Ben Skeggs6ee73862009-12-11 19:24:15 +100051int
Francisco Jerezc88c2e02010-07-24 17:37:33 +020052nv50_display_early_init(struct drm_device *dev)
53{
54 return 0;
55}
56
57void
58nv50_display_late_takedown(struct drm_device *dev)
59{
60}
61
62int
Ben Skeggs6ee73862009-12-11 19:24:15 +100063nv50_display_init(struct drm_device *dev)
64{
65 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsee2e0132010-07-26 09:28:25 +100066 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
Ben Skeggs6ee73862009-12-11 19:24:15 +100067 struct drm_connector *connector;
Ben Skeggsb7bc6132010-10-19 13:05:51 +100068 struct nouveau_channel *evo;
Ben Skeggs6ee73862009-12-11 19:24:15 +100069 int ret, i;
Ben Skeggscbb4b602010-10-18 12:34:04 +100070 u32 val;
Ben Skeggs6ee73862009-12-11 19:24:15 +100071
Maarten Maathuisef2bb502009-12-13 16:53:12 +010072 NV_DEBUG_KMS(dev, "\n");
Ben Skeggs6ee73862009-12-11 19:24:15 +100073
74 nv_wr32(dev, 0x00610184, nv_rd32(dev, 0x00614004));
Ben Skeggs106ddad2010-10-19 11:14:17 +100075
Ben Skeggs6ee73862009-12-11 19:24:15 +100076 /*
77 * I think the 0x006101XX range is some kind of main control area
78 * that enables things.
79 */
80 /* CRTC? */
81 for (i = 0; i < 2; i++) {
82 val = nv_rd32(dev, 0x00616100 + (i * 0x800));
83 nv_wr32(dev, 0x00610190 + (i * 0x10), val);
84 val = nv_rd32(dev, 0x00616104 + (i * 0x800));
85 nv_wr32(dev, 0x00610194 + (i * 0x10), val);
86 val = nv_rd32(dev, 0x00616108 + (i * 0x800));
87 nv_wr32(dev, 0x00610198 + (i * 0x10), val);
88 val = nv_rd32(dev, 0x0061610c + (i * 0x800));
89 nv_wr32(dev, 0x0061019c + (i * 0x10), val);
90 }
Ben Skeggs106ddad2010-10-19 11:14:17 +100091
Ben Skeggs6ee73862009-12-11 19:24:15 +100092 /* DAC */
93 for (i = 0; i < 3; i++) {
94 val = nv_rd32(dev, 0x0061a000 + (i * 0x800));
95 nv_wr32(dev, 0x006101d0 + (i * 0x04), val);
96 }
Ben Skeggs106ddad2010-10-19 11:14:17 +100097
Ben Skeggs6ee73862009-12-11 19:24:15 +100098 /* SOR */
Ben Skeggs8597a1b2010-09-06 11:39:25 +100099 for (i = 0; i < nv50_sor_nr(dev); i++) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000100 val = nv_rd32(dev, 0x0061c000 + (i * 0x800));
101 nv_wr32(dev, 0x006101e0 + (i * 0x04), val);
102 }
Ben Skeggs106ddad2010-10-19 11:14:17 +1000103
Ben Skeggs8597a1b2010-09-06 11:39:25 +1000104 /* EXT */
Ben Skeggs6ee73862009-12-11 19:24:15 +1000105 for (i = 0; i < 3; i++) {
106 val = nv_rd32(dev, 0x0061e000 + (i * 0x800));
107 nv_wr32(dev, 0x006101f0 + (i * 0x04), val);
108 }
109
110 for (i = 0; i < 3; i++) {
111 nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(i), 0x00550000 |
112 NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
113 nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(i), 0x00000001);
114 }
115
Ben Skeggs6ee73862009-12-11 19:24:15 +1000116 /* The precise purpose is unknown, i suspect it has something to do
117 * with text mode.
118 */
119 if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) {
120 nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100);
121 nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1);
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200122 if (!nv_wait(dev, 0x006194e8, 2, 0)) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000123 NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n");
124 NV_ERROR(dev, "0x6194e8 = 0x%08x\n",
125 nv_rd32(dev, 0x6194e8));
126 return -EBUSY;
127 }
128 }
129
Ben Skeggs6ee73862009-12-11 19:24:15 +1000130 for (i = 0; i < 2; i++) {
131 nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000);
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200132 if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
Ben Skeggs6ee73862009-12-11 19:24:15 +1000133 NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
134 NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
135 NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
136 nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
137 return -EBUSY;
138 }
139
140 nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
141 NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON);
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200142 if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
Ben Skeggs6ee73862009-12-11 19:24:15 +1000143 NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS,
144 NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) {
145 NV_ERROR(dev, "timeout: "
146 "CURSOR_CTRL2_STATUS_ACTIVE(%d)\n", i);
147 NV_ERROR(dev, "CURSOR_CTRL2(%d) = 0x%08x\n", i,
148 nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
149 return -EBUSY;
150 }
151 }
152
Ben Skeggs106ddad2010-10-19 11:14:17 +1000153 nv_wr32(dev, NV50_PDISPLAY_PIO_CTRL, 0x00000000);
Ben Skeggs106ddad2010-10-19 11:14:17 +1000154 nv_mask(dev, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000);
Ben Skeggs97e20002010-10-20 14:23:29 +1000155 nv_wr32(dev, NV50_PDISPLAY_INTR_EN_0, 0x00000000);
Ben Skeggs106ddad2010-10-19 11:14:17 +1000156 nv_mask(dev, NV50_PDISPLAY_INTR_1, 0x00000000, 0x00000000);
Ben Skeggs97e20002010-10-20 14:23:29 +1000157 nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1,
158 NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 |
159 NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 |
160 NV50_PDISPLAY_INTR_EN_1_CLK_UNK40);
Ben Skeggs106ddad2010-10-19 11:14:17 +1000161
162 /* enable hotplug interrupts */
163 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
164 struct nouveau_connector *conn = nouveau_connector(connector);
165
166 if (conn->dcb->gpio_tag == 0xff)
167 continue;
168
169 pgpio->irq_enable(dev, conn->dcb->gpio_tag, true);
170 }
171
Ben Skeggsb7bc6132010-10-19 13:05:51 +1000172 ret = nv50_evo_init(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000173 if (ret)
174 return ret;
Ben Skeggsef8389a2011-02-01 10:07:32 +1000175 evo = nv50_display(dev)->evo;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000176
Ben Skeggsb7bc6132010-10-19 13:05:51 +1000177 nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000178
179 ret = RING_SPACE(evo, 11);
180 if (ret)
181 return ret;
182 BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2);
183 OUT_RING(evo, NV50_EVO_UNK84_NOTIFY_DISABLED);
184 OUT_RING(evo, NV50_EVO_DMA_NOTIFY_HANDLE_NONE);
185 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, FB_DMA), 1);
186 OUT_RING(evo, NV50_EVO_CRTC_FB_DMA_HANDLE_NONE);
187 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK0800), 1);
188 OUT_RING(evo, 0);
189 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, DISPLAY_START), 1);
190 OUT_RING(evo, 0);
191 BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1);
192 OUT_RING(evo, 0);
193 FIRE_RING(evo);
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200194 if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2))
Ben Skeggs6ee73862009-12-11 19:24:15 +1000195 NV_ERROR(dev, "evo pushbuf stalled\n");
196
Ben Skeggs6ee73862009-12-11 19:24:15 +1000197
198 return 0;
199}
200
201static int nv50_display_disable(struct drm_device *dev)
202{
203 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsef8389a2011-02-01 10:07:32 +1000204 struct nv50_display *disp = nv50_display(dev);
205 struct nouveau_channel *evo = disp->evo;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000206 struct drm_crtc *drm_crtc;
207 int ret, i;
208
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100209 NV_DEBUG_KMS(dev, "\n");
Ben Skeggs6ee73862009-12-11 19:24:15 +1000210
211 list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
212 struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc);
213
214 nv50_crtc_blank(crtc, true);
215 }
216
Ben Skeggsef8389a2011-02-01 10:07:32 +1000217 ret = RING_SPACE(evo, 2);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000218 if (ret == 0) {
Ben Skeggsef8389a2011-02-01 10:07:32 +1000219 BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
220 OUT_RING(evo, 0);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000221 }
Ben Skeggsef8389a2011-02-01 10:07:32 +1000222 FIRE_RING(evo);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000223
224 /* Almost like ack'ing a vblank interrupt, maybe in the spirit of
225 * cleaning up?
226 */
227 list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
228 struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc);
229 uint32_t mask = NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(crtc->index);
230
231 if (!crtc->base.enabled)
232 continue;
233
234 nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask);
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200235 if (!nv_wait(dev, NV50_PDISPLAY_INTR_1, mask, mask)) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000236 NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == "
237 "0x%08x\n", mask, mask);
238 NV_ERROR(dev, "0x610024 = 0x%08x\n",
239 nv_rd32(dev, NV50_PDISPLAY_INTR_1));
240 }
241 }
242
Ben Skeggsb7bc6132010-10-19 13:05:51 +1000243 nv50_evo_fini(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000244
245 for (i = 0; i < 3; i++) {
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200246 if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i),
Ben Skeggs6ee73862009-12-11 19:24:15 +1000247 NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
248 NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i);
249 NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i,
250 nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i)));
251 }
252 }
253
254 /* disable interrupts. */
Ben Skeggs97e20002010-10-20 14:23:29 +1000255 nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1, 0x00000000);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000256
257 /* disable hotplug interrupts */
258 nv_wr32(dev, 0xe054, 0xffffffff);
259 nv_wr32(dev, 0xe050, 0x00000000);
260 if (dev_priv->chipset >= 0x90) {
261 nv_wr32(dev, 0xe074, 0xffffffff);
262 nv_wr32(dev, 0xe070, 0x00000000);
263 }
264 return 0;
265}
266
267int nv50_display_create(struct drm_device *dev)
268{
269 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs04a39c52010-02-24 10:03:05 +1000270 struct dcb_table *dcb = &dev_priv->vbios.dcb;
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000271 struct drm_connector *connector, *ct;
Ben Skeggsef8389a2011-02-01 10:07:32 +1000272 struct nv50_display *priv;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000273 int ret, i;
274
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100275 NV_DEBUG_KMS(dev, "\n");
Ben Skeggs6ee73862009-12-11 19:24:15 +1000276
Ben Skeggsef8389a2011-02-01 10:07:32 +1000277 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
278 if (!priv)
279 return -ENOMEM;
280 dev_priv->engine.display.priv = priv;
281
Ben Skeggs6ee73862009-12-11 19:24:15 +1000282 /* init basic kernel modesetting */
283 drm_mode_config_init(dev);
284
285 /* Initialise some optional connector properties. */
286 drm_mode_create_scaling_mode_property(dev);
287 drm_mode_create_dithering_property(dev);
288
289 dev->mode_config.min_width = 0;
290 dev->mode_config.min_height = 0;
291
292 dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs;
293
294 dev->mode_config.max_width = 8192;
295 dev->mode_config.max_height = 8192;
296
297 dev->mode_config.fb_base = dev_priv->fb_phys;
298
Ben Skeggs6ee73862009-12-11 19:24:15 +1000299 /* Create CRTC objects */
300 for (i = 0; i < 2; i++)
301 nv50_crtc_create(dev, i);
302
303 /* We setup the encoders from the BIOS table */
304 for (i = 0 ; i < dcb->entries; i++) {
305 struct dcb_entry *entry = &dcb->entry[i];
306
307 if (entry->location != DCB_LOC_ON_CHIP) {
308 NV_WARN(dev, "Off-chip encoder %d/%d unsupported\n",
309 entry->type, ffs(entry->or) - 1);
310 continue;
311 }
312
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000313 connector = nouveau_connector_create(dev, entry->connector);
314 if (IS_ERR(connector))
315 continue;
316
Ben Skeggs6ee73862009-12-11 19:24:15 +1000317 switch (entry->type) {
318 case OUTPUT_TMDS:
319 case OUTPUT_LVDS:
320 case OUTPUT_DP:
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000321 nv50_sor_create(connector, entry);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000322 break;
323 case OUTPUT_ANALOG:
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000324 nv50_dac_create(connector, entry);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000325 break;
326 default:
327 NV_WARN(dev, "DCB encoder %d unknown\n", entry->type);
328 continue;
329 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000330 }
331
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000332 list_for_each_entry_safe(connector, ct,
333 &dev->mode_config.connector_list, head) {
334 if (!connector->encoder_ids[0]) {
335 NV_WARN(dev, "%s has no encoders, removing\n",
336 drm_get_connector_name(connector));
337 connector->funcs->destroy(connector);
338 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000339 }
340
Ben Skeggs19b7fc72010-11-03 10:27:27 +1000341 INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
342 nouveau_irq_register(dev, 26, nv50_display_isr);
343
Ben Skeggs6ee73862009-12-11 19:24:15 +1000344 ret = nv50_display_init(dev);
Ben Skeggsa1663ed2010-03-25 16:01:04 +1000345 if (ret) {
346 nv50_display_destroy(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000347 return ret;
Ben Skeggsa1663ed2010-03-25 16:01:04 +1000348 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000349
350 return 0;
351}
352
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200353void
354nv50_display_destroy(struct drm_device *dev)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000355{
Tejun Heod82f8e62011-01-26 17:49:18 +0100356 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsef8389a2011-02-01 10:07:32 +1000357 struct nv50_display *disp = nv50_display(dev);
Tejun Heod82f8e62011-01-26 17:49:18 +0100358
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100359 NV_DEBUG_KMS(dev, "\n");
Ben Skeggs6ee73862009-12-11 19:24:15 +1000360
361 drm_mode_config_cleanup(dev);
362
363 nv50_display_disable(dev);
Ben Skeggs19b7fc72010-11-03 10:27:27 +1000364 nouveau_irq_unregister(dev, 26);
Tejun Heod82f8e62011-01-26 17:49:18 +0100365 flush_work_sync(&dev_priv->irq_work);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000366 kfree(disp);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000367}
368
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000369static u16
370nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
371 u32 mc, int pxclk)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000372{
373 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs75c722d2009-12-21 12:16:52 +1000374 struct nouveau_connector *nv_connector = NULL;
375 struct drm_encoder *encoder;
Ben Skeggs04a39c52010-02-24 10:03:05 +1000376 struct nvbios *bios = &dev_priv->vbios;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000377 u32 script = 0, or;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000378
Ben Skeggs75c722d2009-12-21 12:16:52 +1000379 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
380 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
381
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000382 if (nv_encoder->dcb != dcb)
Ben Skeggs75c722d2009-12-21 12:16:52 +1000383 continue;
384
385 nv_connector = nouveau_encoder_connector_get(nv_encoder);
386 break;
387 }
388
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000389 or = ffs(dcb->or) - 1;
390 switch (dcb->type) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000391 case OUTPUT_LVDS:
392 script = (mc >> 8) & 0xf;
Ben Skeggs04a39c52010-02-24 10:03:05 +1000393 if (bios->fp_no_ddc) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000394 if (bios->fp.dual_link)
395 script |= 0x0100;
396 if (bios->fp.if_is_24bit)
397 script |= 0x0200;
398 } else {
399 if (pxclk >= bios->fp.duallink_transition_clk) {
400 script |= 0x0100;
401 if (bios->fp.strapless_is_24bit & 2)
402 script |= 0x0200;
403 } else
404 if (bios->fp.strapless_is_24bit & 1)
405 script |= 0x0200;
Ben Skeggs75c722d2009-12-21 12:16:52 +1000406
407 if (nv_connector && nv_connector->edid &&
408 (nv_connector->edid->revision >= 4) &&
409 (nv_connector->edid->input & 0x70) >= 0x20)
410 script |= 0x0200;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000411 }
412
413 if (nouveau_uscript_lvds >= 0) {
414 NV_INFO(dev, "override script 0x%04x with 0x%04x "
415 "for output LVDS-%d\n", script,
416 nouveau_uscript_lvds, or);
417 script = nouveau_uscript_lvds;
418 }
419 break;
420 case OUTPUT_TMDS:
421 script = (mc >> 8) & 0xf;
422 if (pxclk >= 165000)
423 script |= 0x0100;
424
425 if (nouveau_uscript_tmds >= 0) {
426 NV_INFO(dev, "override script 0x%04x with 0x%04x "
427 "for output TMDS-%d\n", script,
428 nouveau_uscript_tmds, or);
429 script = nouveau_uscript_tmds;
430 }
431 break;
432 case OUTPUT_DP:
433 script = (mc >> 8) & 0xf;
434 break;
435 case OUTPUT_ANALOG:
436 script = 0xff;
437 break;
438 default:
439 NV_ERROR(dev, "modeset on unsupported output type!\n");
440 break;
441 }
442
443 return script;
444}
445
446static void
447nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
448{
449 struct drm_nouveau_private *dev_priv = dev->dev_private;
Francisco Jerez042206c2010-10-21 18:19:29 +0200450 struct nouveau_channel *chan, *tmp;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000451
Francisco Jerez042206c2010-10-21 18:19:29 +0200452 list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting,
453 nvsw.vbl_wait) {
Francisco Jerez1f6d2de2010-10-24 14:15:58 +0200454 if (chan->nvsw.vblsem_head != crtc)
455 continue;
456
Ben Skeggs6ee73862009-12-11 19:24:15 +1000457 nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset,
458 chan->nvsw.vblsem_rval);
459 list_del(&chan->nvsw.vbl_wait);
Francisco Jerez042206c2010-10-21 18:19:29 +0200460 drm_vblank_put(dev, crtc);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000461 }
Francisco Jerez042206c2010-10-21 18:19:29 +0200462
463 drm_handle_vblank(dev, crtc);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000464}
465
466static void
467nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
468{
Ben Skeggs6ee73862009-12-11 19:24:15 +1000469 if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0)
470 nv50_display_vblank_crtc_handler(dev, 0);
471
472 if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1)
473 nv50_display_vblank_crtc_handler(dev, 1);
474
Francisco Jerez042206c2010-10-21 18:19:29 +0200475 nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_VBLANK_CRTC);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000476}
477
478static void
479nv50_display_unk10_handler(struct drm_device *dev)
480{
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000481 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsef8389a2011-02-01 10:07:32 +1000482 struct nv50_display *disp = nv50_display(dev);
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000483 u32 unk30 = nv_rd32(dev, 0x610030), mc;
484 int i, crtc, or, type = OUTPUT_ANY;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000485
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000486 NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000487 disp->irq.dcb = NULL;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000488
489 nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8);
490
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000491 /* Determine which CRTC we're dealing with, only 1 ever will be
492 * signalled at the same time with the current nouveau code.
493 */
494 crtc = ffs((unk30 & 0x00000060) >> 5) - 1;
495 if (crtc < 0)
496 goto ack;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000497
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000498 /* Nothing needs to be done for the encoder */
499 crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
500 if (crtc < 0)
501 goto ack;
502
503 /* Find which encoder was connected to the CRTC */
504 for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
505 mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
506 NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
507 if (!(mc & (1 << crtc)))
508 continue;
509
510 switch ((mc & 0x00000f00) >> 8) {
511 case 0: type = OUTPUT_ANALOG; break;
512 case 1: type = OUTPUT_TV; break;
513 default:
514 NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
515 goto ack;
516 }
517
518 or = i;
519 }
520
Ben Skeggs8597a1b2010-09-06 11:39:25 +1000521 for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000522 if (dev_priv->chipset < 0x90 ||
523 dev_priv->chipset == 0x92 ||
524 dev_priv->chipset == 0xa0)
525 mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
526 else
527 mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
528
529 NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
530 if (!(mc & (1 << crtc)))
531 continue;
532
533 switch ((mc & 0x00000f00) >> 8) {
534 case 0: type = OUTPUT_LVDS; break;
535 case 1: type = OUTPUT_TMDS; break;
536 case 2: type = OUTPUT_TMDS; break;
537 case 5: type = OUTPUT_TMDS; break;
538 case 8: type = OUTPUT_DP; break;
539 case 9: type = OUTPUT_DP; break;
540 default:
541 NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
542 goto ack;
543 }
544
545 or = i;
546 }
547
548 /* There was no encoder to disable */
549 if (type == OUTPUT_ANY)
550 goto ack;
551
552 /* Disable the encoder */
553 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
554 struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
555
556 if (dcb->type == type && (dcb->or & (1 << or))) {
557 nouveau_bios_run_display_table(dev, dcb, 0, -1);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000558 disp->irq.dcb = dcb;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000559 goto ack;
560 }
561 }
562
563 NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000564ack:
565 nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10);
566 nv_wr32(dev, 0x610030, 0x80000000);
567}
568
569static void
Ben Skeggsafa3b4c2010-04-23 08:21:48 +1000570nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
571{
572 int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
573 struct drm_encoder *encoder;
574 uint32_t tmp, unk0 = 0, unk1 = 0;
575
576 if (dcb->type != OUTPUT_DP)
577 return;
578
579 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
580 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
581
582 if (nv_encoder->dcb == dcb) {
583 unk0 = nv_encoder->dp.unk0;
584 unk1 = nv_encoder->dp.unk1;
585 break;
586 }
587 }
588
589 if (unk0 || unk1) {
590 tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
591 tmp &= 0xfffffe03;
592 nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp | unk0);
593
594 tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
595 tmp &= 0xfef080c0;
596 nv_wr32(dev, NV50_SOR_DP_UNK128(or, link), tmp | unk1);
597 }
598}
599
600static void
Ben Skeggs6ee73862009-12-11 19:24:15 +1000601nv50_display_unk20_handler(struct drm_device *dev)
602{
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000603 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsef8389a2011-02-01 10:07:32 +1000604 struct nv50_display *disp = nv50_display(dev);
Ben Skeggsea5f2782011-01-31 08:26:04 +1000605 u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc = 0;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000606 struct dcb_entry *dcb;
607 int i, crtc, or, type = OUTPUT_ANY;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000608
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000609 NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000610 dcb = disp->irq.dcb;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000611 if (dcb) {
612 nouveau_bios_run_display_table(dev, dcb, 0, -2);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000613 disp->irq.dcb = NULL;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000614 }
615
616 /* CRTC clock change requested? */
617 crtc = ffs((unk30 & 0x00000600) >> 9) - 1;
618 if (crtc >= 0) {
619 pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK));
620 pclk &= 0x003fffff;
621
622 nv50_crtc_set_clock(dev, crtc, pclk);
623
624 tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc));
625 tmp &= ~0x000000f;
626 nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp);
627 }
628
629 /* Nothing needs to be done for the encoder */
630 crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
631 if (crtc < 0)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000632 goto ack;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000633 pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000634
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000635 /* Find which encoder is connected to the CRTC */
636 for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
637 mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i));
638 NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
639 if (!(mc & (1 << crtc)))
640 continue;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000641
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000642 switch ((mc & 0x00000f00) >> 8) {
643 case 0: type = OUTPUT_ANALOG; break;
644 case 1: type = OUTPUT_TV; break;
645 default:
646 NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
647 goto ack;
648 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000649
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000650 or = i;
651 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000652
Ben Skeggs8597a1b2010-09-06 11:39:25 +1000653 for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000654 if (dev_priv->chipset < 0x90 ||
655 dev_priv->chipset == 0x92 ||
656 dev_priv->chipset == 0xa0)
657 mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i));
658 else
659 mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i));
Ben Skeggs6ee73862009-12-11 19:24:15 +1000660
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000661 NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
662 if (!(mc & (1 << crtc)))
663 continue;
Ben Skeggsafa3b4c2010-04-23 08:21:48 +1000664
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000665 switch ((mc & 0x00000f00) >> 8) {
666 case 0: type = OUTPUT_LVDS; break;
667 case 1: type = OUTPUT_TMDS; break;
668 case 2: type = OUTPUT_TMDS; break;
669 case 5: type = OUTPUT_TMDS; break;
670 case 8: type = OUTPUT_DP; break;
671 case 9: type = OUTPUT_DP; break;
672 default:
673 NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
674 goto ack;
675 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000676
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000677 or = i;
678 }
679
680 if (type == OUTPUT_ANY)
681 goto ack;
682
683 /* Enable the encoder */
684 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
685 dcb = &dev_priv->vbios.dcb.entry[i];
686 if (dcb->type == type && (dcb->or & (1 << or)))
687 break;
688 }
689
690 if (i == dev_priv->vbios.dcb.entries) {
691 NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
692 goto ack;
693 }
694
695 script = nv50_display_script_select(dev, dcb, mc, pclk);
696 nouveau_bios_run_display_table(dev, dcb, script, pclk);
697
698 nv50_display_unk20_dp_hack(dev, dcb);
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000699
700 if (dcb->type != OUTPUT_ANALOG) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000701 tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
702 tmp &= ~0x00000f0f;
703 if (script & 0x0100)
704 tmp |= 0x00000101;
705 nv_wr32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or), tmp);
706 } else {
707 nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
708 }
709
Ben Skeggsef8389a2011-02-01 10:07:32 +1000710 disp->irq.dcb = dcb;
711 disp->irq.pclk = pclk;
712 disp->irq.script = script;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000713
Ben Skeggs6ee73862009-12-11 19:24:15 +1000714ack:
715 nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20);
716 nv_wr32(dev, 0x610030, 0x80000000);
717}
718
Ben Skeggs271f29e2010-07-09 10:37:42 +1000719/* If programming a TMDS output on a SOR that can also be configured for
720 * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
721 *
722 * It looks like the VBIOS TMDS scripts make an attempt at this, however,
723 * the VBIOS scripts on at least one board I have only switch it off on
724 * link 0, causing a blank display if the output has previously been
725 * programmed for DisplayPort.
726 */
727static void
728nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb)
729{
730 int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
731 struct drm_encoder *encoder;
732 u32 tmp;
733
734 if (dcb->type != OUTPUT_TMDS)
735 return;
736
737 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
738 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
739
740 if (nv_encoder->dcb->type == OUTPUT_DP &&
741 nv_encoder->dcb->or & (1 << or)) {
742 tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
743 tmp &= ~NV50_SOR_DP_CTRL_ENABLED;
744 nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
745 break;
746 }
747 }
748}
749
Ben Skeggs6ee73862009-12-11 19:24:15 +1000750static void
751nv50_display_unk40_handler(struct drm_device *dev)
752{
Ben Skeggsef8389a2011-02-01 10:07:32 +1000753 struct nv50_display *disp = nv50_display(dev);
754 struct dcb_entry *dcb = disp->irq.dcb;
755 u16 script = disp->irq.script;
756 u32 unk30 = nv_rd32(dev, 0x610030), pclk = disp->irq.pclk;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000757
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000758 NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000759 disp->irq.dcb = NULL;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000760 if (!dcb)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000761 goto ack;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000762
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000763 nouveau_bios_run_display_table(dev, dcb, script, -pclk);
Ben Skeggs271f29e2010-07-09 10:37:42 +1000764 nv50_display_unk40_dp_set_tmds(dev, dcb);
765
Ben Skeggs6ee73862009-12-11 19:24:15 +1000766ack:
767 nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40);
768 nv_wr32(dev, 0x610030, 0x80000000);
769 nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) | 8);
770}
771
772void
773nv50_display_irq_handler_bh(struct work_struct *work)
774{
775 struct drm_nouveau_private *dev_priv =
776 container_of(work, struct drm_nouveau_private, irq_work);
777 struct drm_device *dev = dev_priv->dev;
778
779 for (;;) {
780 uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
781 uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
782
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100783 NV_DEBUG_KMS(dev, "PDISPLAY_INTR_BH 0x%08x 0x%08x\n", intr0, intr1);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000784
785 if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK10)
786 nv50_display_unk10_handler(dev);
787 else
788 if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK20)
789 nv50_display_unk20_handler(dev);
790 else
791 if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK40)
792 nv50_display_unk40_handler(dev);
793 else
794 break;
795 }
796
797 nv_wr32(dev, NV03_PMC_INTR_EN_0, 1);
798}
799
800static void
801nv50_display_error_handler(struct drm_device *dev)
802{
Ben Skeggs97e20002010-10-20 14:23:29 +1000803 u32 channels = (nv_rd32(dev, NV50_PDISPLAY_INTR_0) & 0x001f0000) >> 16;
804 u32 addr, data;
805 int chid;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000806
Ben Skeggs97e20002010-10-20 14:23:29 +1000807 for (chid = 0; chid < 5; chid++) {
808 if (!(channels & (1 << chid)))
809 continue;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000810
Ben Skeggs97e20002010-10-20 14:23:29 +1000811 nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000 << chid);
812 addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid));
813 data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA(chid));
814 NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x "
815 "(0x%04x 0x%02x)\n", chid,
816 addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000817
Ben Skeggs97e20002010-10-20 14:23:29 +1000818 nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid), 0x90000000);
819 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000820}
821
Ben Skeggs19b7fc72010-11-03 10:27:27 +1000822static void
823nv50_display_isr(struct drm_device *dev)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000824{
825 struct drm_nouveau_private *dev_priv = dev->dev_private;
826 uint32_t delayed = 0;
827
Ben Skeggs6ee73862009-12-11 19:24:15 +1000828 while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
829 uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
830 uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
831 uint32_t clock;
832
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100833 NV_DEBUG_KMS(dev, "PDISPLAY_INTR 0x%08x 0x%08x\n", intr0, intr1);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000834
835 if (!intr0 && !(intr1 & ~delayed))
836 break;
837
Ben Skeggs97e20002010-10-20 14:23:29 +1000838 if (intr0 & 0x001f0000) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000839 nv50_display_error_handler(dev);
Ben Skeggs97e20002010-10-20 14:23:29 +1000840 intr0 &= ~0x001f0000;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000841 }
842
843 if (intr1 & NV50_PDISPLAY_INTR_1_VBLANK_CRTC) {
844 nv50_display_vblank_handler(dev, intr1);
845 intr1 &= ~NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
846 }
847
848 clock = (intr1 & (NV50_PDISPLAY_INTR_1_CLK_UNK10 |
849 NV50_PDISPLAY_INTR_1_CLK_UNK20 |
850 NV50_PDISPLAY_INTR_1_CLK_UNK40));
851 if (clock) {
852 nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
853 if (!work_pending(&dev_priv->irq_work))
Tejun Heod82f8e62011-01-26 17:49:18 +0100854 schedule_work(&dev_priv->irq_work);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000855 delayed |= clock;
856 intr1 &= ~clock;
857 }
858
859 if (intr0) {
860 NV_ERROR(dev, "unknown PDISPLAY_INTR_0: 0x%08x\n", intr0);
861 nv_wr32(dev, NV50_PDISPLAY_INTR_0, intr0);
862 }
863
864 if (intr1) {
865 NV_ERROR(dev,
866 "unknown PDISPLAY_INTR_1: 0x%08x\n", intr1);
867 nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr1);
868 }
869 }
870}