blob: a37e32e00ec832549ff8f82ced04c3d14b13bda7 [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
Ben Skeggs8348f362011-02-03 16:07:44 +100027#define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
Ben Skeggs6ee73862009-12-11 19:24:15 +100028#include "nv50_display.h"
29#include "nouveau_crtc.h"
30#include "nouveau_encoder.h"
31#include "nouveau_connector.h"
32#include "nouveau_fb.h"
Dave Airlie4abe3522010-03-30 05:34:18 +000033#include "nouveau_fbcon.h"
Ben Skeggsa8eaebc2010-09-01 15:24:31 +100034#include "nouveau_ramht.h"
Ben Skeggs6ee73862009-12-11 19:24:15 +100035#include "drm_crtc_helper.h"
36
Ben Skeggs19b7fc72010-11-03 10:27:27 +100037static void nv50_display_isr(struct drm_device *);
Ben Skeggsf13e4352011-02-03 20:06:14 +100038static void nv50_display_bh(unsigned long);
Ben Skeggs19b7fc72010-11-03 10:27:27 +100039
Ben Skeggs8597a1b2010-09-06 11:39:25 +100040static inline int
41nv50_sor_nr(struct drm_device *dev)
42{
43 struct drm_nouveau_private *dev_priv = dev->dev_private;
44
45 if (dev_priv->chipset < 0x90 ||
46 dev_priv->chipset == 0x92 ||
47 dev_priv->chipset == 0xa0)
48 return 2;
49
50 return 4;
51}
52
Ben Skeggs6ee73862009-12-11 19:24:15 +100053int
Francisco Jerezc88c2e02010-07-24 17:37:33 +020054nv50_display_early_init(struct drm_device *dev)
55{
56 return 0;
57}
58
59void
60nv50_display_late_takedown(struct drm_device *dev)
61{
62}
63
64int
Ben Skeggse6e039d2011-10-14 14:35:19 +100065nv50_display_sync(struct drm_device *dev)
66{
67 struct drm_nouveau_private *dev_priv = dev->dev_private;
68 struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
69 struct nv50_display *disp = nv50_display(dev);
70 struct nouveau_channel *evo = disp->master;
71 u64 start;
72 int ret;
73
74 ret = RING_SPACE(evo, 6);
75 if (ret == 0) {
76 BEGIN_RING(evo, 0, 0x0084, 1);
77 OUT_RING (evo, 0x80000000);
78 BEGIN_RING(evo, 0, 0x0080, 1);
79 OUT_RING (evo, 0);
80 BEGIN_RING(evo, 0, 0x0084, 1);
81 OUT_RING (evo, 0x00000000);
82
83 nv_wo32(disp->ntfy, 0x000, 0x00000000);
84 FIRE_RING (evo);
85
86 start = ptimer->read(dev);
87 do {
88 if (nv_ro32(disp->ntfy, 0x000))
89 return 0;
90 } while (ptimer->read(dev) - start < 2000000000ULL);
91 }
92
93 return -EBUSY;
94}
95
96int
Ben Skeggs6ee73862009-12-11 19:24:15 +100097nv50_display_init(struct drm_device *dev)
98{
99 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsee2e0132010-07-26 09:28:25 +1000100 struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000101 struct drm_connector *connector;
Ben Skeggsb7bc6132010-10-19 13:05:51 +1000102 struct nouveau_channel *evo;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000103 int ret, i;
Ben Skeggscbb4b602010-10-18 12:34:04 +1000104 u32 val;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000105
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100106 NV_DEBUG_KMS(dev, "\n");
Ben Skeggs6ee73862009-12-11 19:24:15 +1000107
108 nv_wr32(dev, 0x00610184, nv_rd32(dev, 0x00614004));
Ben Skeggs106ddad2010-10-19 11:14:17 +1000109
Ben Skeggs6ee73862009-12-11 19:24:15 +1000110 /*
111 * I think the 0x006101XX range is some kind of main control area
112 * that enables things.
113 */
114 /* CRTC? */
115 for (i = 0; i < 2; i++) {
116 val = nv_rd32(dev, 0x00616100 + (i * 0x800));
117 nv_wr32(dev, 0x00610190 + (i * 0x10), val);
118 val = nv_rd32(dev, 0x00616104 + (i * 0x800));
119 nv_wr32(dev, 0x00610194 + (i * 0x10), val);
120 val = nv_rd32(dev, 0x00616108 + (i * 0x800));
121 nv_wr32(dev, 0x00610198 + (i * 0x10), val);
122 val = nv_rd32(dev, 0x0061610c + (i * 0x800));
123 nv_wr32(dev, 0x0061019c + (i * 0x10), val);
124 }
Ben Skeggs106ddad2010-10-19 11:14:17 +1000125
Ben Skeggs6ee73862009-12-11 19:24:15 +1000126 /* DAC */
127 for (i = 0; i < 3; i++) {
128 val = nv_rd32(dev, 0x0061a000 + (i * 0x800));
129 nv_wr32(dev, 0x006101d0 + (i * 0x04), val);
130 }
Ben Skeggs106ddad2010-10-19 11:14:17 +1000131
Ben Skeggs6ee73862009-12-11 19:24:15 +1000132 /* SOR */
Ben Skeggs8597a1b2010-09-06 11:39:25 +1000133 for (i = 0; i < nv50_sor_nr(dev); i++) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000134 val = nv_rd32(dev, 0x0061c000 + (i * 0x800));
135 nv_wr32(dev, 0x006101e0 + (i * 0x04), val);
136 }
Ben Skeggs106ddad2010-10-19 11:14:17 +1000137
Ben Skeggs8597a1b2010-09-06 11:39:25 +1000138 /* EXT */
Ben Skeggs6ee73862009-12-11 19:24:15 +1000139 for (i = 0; i < 3; i++) {
140 val = nv_rd32(dev, 0x0061e000 + (i * 0x800));
141 nv_wr32(dev, 0x006101f0 + (i * 0x04), val);
142 }
143
144 for (i = 0; i < 3; i++) {
145 nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(i), 0x00550000 |
146 NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
147 nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(i), 0x00000001);
148 }
149
Ben Skeggs6ee73862009-12-11 19:24:15 +1000150 /* The precise purpose is unknown, i suspect it has something to do
151 * with text mode.
152 */
153 if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) {
154 nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100);
155 nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1);
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200156 if (!nv_wait(dev, 0x006194e8, 2, 0)) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000157 NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n");
158 NV_ERROR(dev, "0x6194e8 = 0x%08x\n",
159 nv_rd32(dev, 0x6194e8));
160 return -EBUSY;
161 }
162 }
163
Ben Skeggs6ee73862009-12-11 19:24:15 +1000164 for (i = 0; i < 2; i++) {
165 nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000);
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200166 if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
Ben Skeggs6ee73862009-12-11 19:24:15 +1000167 NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
168 NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
169 NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
170 nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
171 return -EBUSY;
172 }
173
174 nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
175 NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON);
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200176 if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
Ben Skeggs6ee73862009-12-11 19:24:15 +1000177 NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS,
178 NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) {
179 NV_ERROR(dev, "timeout: "
180 "CURSOR_CTRL2_STATUS_ACTIVE(%d)\n", i);
181 NV_ERROR(dev, "CURSOR_CTRL2(%d) = 0x%08x\n", i,
182 nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
183 return -EBUSY;
184 }
185 }
186
Ben Skeggs106ddad2010-10-19 11:14:17 +1000187 nv_wr32(dev, NV50_PDISPLAY_PIO_CTRL, 0x00000000);
Ben Skeggs106ddad2010-10-19 11:14:17 +1000188 nv_mask(dev, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000);
Ben Skeggs97e20002010-10-20 14:23:29 +1000189 nv_wr32(dev, NV50_PDISPLAY_INTR_EN_0, 0x00000000);
Ben Skeggs106ddad2010-10-19 11:14:17 +1000190 nv_mask(dev, NV50_PDISPLAY_INTR_1, 0x00000000, 0x00000000);
Ben Skeggs97e20002010-10-20 14:23:29 +1000191 nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1,
192 NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 |
193 NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 |
194 NV50_PDISPLAY_INTR_EN_1_CLK_UNK40);
Ben Skeggs106ddad2010-10-19 11:14:17 +1000195
196 /* enable hotplug interrupts */
197 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
198 struct nouveau_connector *conn = nouveau_connector(connector);
199
200 if (conn->dcb->gpio_tag == 0xff)
201 continue;
202
203 pgpio->irq_enable(dev, conn->dcb->gpio_tag, true);
204 }
205
Ben Skeggsb7bc6132010-10-19 13:05:51 +1000206 ret = nv50_evo_init(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000207 if (ret)
208 return ret;
Ben Skeggs59c0f572011-02-01 10:24:41 +1000209 evo = nv50_display(dev)->master;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000210
Ben Skeggsb7bc6132010-10-19 13:05:51 +1000211 nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000212
Ben Skeggsb98e3f52011-10-14 16:13:10 +1000213 ret = RING_SPACE(evo, 3);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000214 if (ret)
215 return ret;
216 BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2);
Ben Skeggsb98e3f52011-10-14 16:13:10 +1000217 OUT_RING (evo, NV50_EVO_UNK84_NOTIFY_DISABLED);
218 OUT_RING (evo, NvEvoSync);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000219
Ben Skeggsb98e3f52011-10-14 16:13:10 +1000220 return nv50_display_sync(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000221}
222
223static int nv50_display_disable(struct drm_device *dev)
224{
225 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsef8389a2011-02-01 10:07:32 +1000226 struct nv50_display *disp = nv50_display(dev);
Ben Skeggs59c0f572011-02-01 10:24:41 +1000227 struct nouveau_channel *evo = disp->master;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000228 struct drm_crtc *drm_crtc;
229 int ret, i;
230
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100231 NV_DEBUG_KMS(dev, "\n");
Ben Skeggs6ee73862009-12-11 19:24:15 +1000232
233 list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
234 struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc);
235
236 nv50_crtc_blank(crtc, true);
237 }
238
Ben Skeggsef8389a2011-02-01 10:07:32 +1000239 ret = RING_SPACE(evo, 2);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000240 if (ret == 0) {
Ben Skeggsef8389a2011-02-01 10:07:32 +1000241 BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
242 OUT_RING(evo, 0);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000243 }
Ben Skeggsef8389a2011-02-01 10:07:32 +1000244 FIRE_RING(evo);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000245
246 /* Almost like ack'ing a vblank interrupt, maybe in the spirit of
247 * cleaning up?
248 */
249 list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
250 struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc);
251 uint32_t mask = NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(crtc->index);
252
253 if (!crtc->base.enabled)
254 continue;
255
256 nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask);
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200257 if (!nv_wait(dev, NV50_PDISPLAY_INTR_1, mask, mask)) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000258 NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == "
259 "0x%08x\n", mask, mask);
260 NV_ERROR(dev, "0x610024 = 0x%08x\n",
261 nv_rd32(dev, NV50_PDISPLAY_INTR_1));
262 }
263 }
264
Ben Skeggs048a8852011-07-04 10:47:19 +1000265 for (i = 0; i < 2; i++) {
266 nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0);
267 if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
268 NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) {
269 NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n");
270 NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n",
271 nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i)));
272 }
273 }
274
Ben Skeggsb7bc6132010-10-19 13:05:51 +1000275 nv50_evo_fini(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000276
277 for (i = 0; i < 3; i++) {
Francisco Jerez4b5c1522010-09-07 17:34:44 +0200278 if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i),
Ben Skeggs6ee73862009-12-11 19:24:15 +1000279 NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
280 NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i);
281 NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i,
282 nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i)));
283 }
284 }
285
286 /* disable interrupts. */
Ben Skeggs97e20002010-10-20 14:23:29 +1000287 nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1, 0x00000000);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000288
289 /* disable hotplug interrupts */
290 nv_wr32(dev, 0xe054, 0xffffffff);
291 nv_wr32(dev, 0xe050, 0x00000000);
292 if (dev_priv->chipset >= 0x90) {
293 nv_wr32(dev, 0xe074, 0xffffffff);
294 nv_wr32(dev, 0xe070, 0x00000000);
295 }
296 return 0;
297}
298
299int nv50_display_create(struct drm_device *dev)
300{
301 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs04a39c52010-02-24 10:03:05 +1000302 struct dcb_table *dcb = &dev_priv->vbios.dcb;
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000303 struct drm_connector *connector, *ct;
Ben Skeggsef8389a2011-02-01 10:07:32 +1000304 struct nv50_display *priv;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000305 int ret, i;
306
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100307 NV_DEBUG_KMS(dev, "\n");
Ben Skeggs6ee73862009-12-11 19:24:15 +1000308
Ben Skeggsef8389a2011-02-01 10:07:32 +1000309 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
310 if (!priv)
311 return -ENOMEM;
312 dev_priv->engine.display.priv = priv;
313
Ben Skeggs6ee73862009-12-11 19:24:15 +1000314 /* Create CRTC objects */
315 for (i = 0; i < 2; i++)
316 nv50_crtc_create(dev, i);
317
318 /* We setup the encoders from the BIOS table */
319 for (i = 0 ; i < dcb->entries; i++) {
320 struct dcb_entry *entry = &dcb->entry[i];
321
322 if (entry->location != DCB_LOC_ON_CHIP) {
323 NV_WARN(dev, "Off-chip encoder %d/%d unsupported\n",
324 entry->type, ffs(entry->or) - 1);
325 continue;
326 }
327
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000328 connector = nouveau_connector_create(dev, entry->connector);
329 if (IS_ERR(connector))
330 continue;
331
Ben Skeggs6ee73862009-12-11 19:24:15 +1000332 switch (entry->type) {
333 case OUTPUT_TMDS:
334 case OUTPUT_LVDS:
335 case OUTPUT_DP:
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000336 nv50_sor_create(connector, entry);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000337 break;
338 case OUTPUT_ANALOG:
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000339 nv50_dac_create(connector, entry);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000340 break;
341 default:
342 NV_WARN(dev, "DCB encoder %d unknown\n", entry->type);
343 continue;
344 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000345 }
346
Ben Skeggs8f1a6082010-06-28 14:35:50 +1000347 list_for_each_entry_safe(connector, ct,
348 &dev->mode_config.connector_list, head) {
349 if (!connector->encoder_ids[0]) {
350 NV_WARN(dev, "%s has no encoders, removing\n",
351 drm_get_connector_name(connector));
352 connector->funcs->destroy(connector);
353 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000354 }
355
Ben Skeggsf13e4352011-02-03 20:06:14 +1000356 tasklet_init(&priv->tasklet, nv50_display_bh, (unsigned long)dev);
Ben Skeggs19b7fc72010-11-03 10:27:27 +1000357 nouveau_irq_register(dev, 26, nv50_display_isr);
358
Ben Skeggs6ee73862009-12-11 19:24:15 +1000359 ret = nv50_display_init(dev);
Ben Skeggsa1663ed2010-03-25 16:01:04 +1000360 if (ret) {
361 nv50_display_destroy(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000362 return ret;
Ben Skeggsa1663ed2010-03-25 16:01:04 +1000363 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000364
365 return 0;
366}
367
Francisco Jerezc88c2e02010-07-24 17:37:33 +0200368void
369nv50_display_destroy(struct drm_device *dev)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000370{
Ben Skeggsef8389a2011-02-01 10:07:32 +1000371 struct nv50_display *disp = nv50_display(dev);
Tejun Heod82f8e62011-01-26 17:49:18 +0100372
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100373 NV_DEBUG_KMS(dev, "\n");
Ben Skeggs6ee73862009-12-11 19:24:15 +1000374
Ben Skeggs6ee73862009-12-11 19:24:15 +1000375 nv50_display_disable(dev);
Ben Skeggs19b7fc72010-11-03 10:27:27 +1000376 nouveau_irq_unregister(dev, 26);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000377 kfree(disp);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000378}
379
Ben Skeggscdccc702011-02-07 13:29:23 +1000380void
381nv50_display_flip_stop(struct drm_crtc *crtc)
382{
383 struct nv50_display *disp = nv50_display(crtc->dev);
384 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
385 struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index];
386 struct nouveau_channel *evo = dispc->sync;
387 int ret;
388
389 ret = RING_SPACE(evo, 8);
390 if (ret) {
391 WARN_ON(1);
392 return;
393 }
394
395 BEGIN_RING(evo, 0, 0x0084, 1);
396 OUT_RING (evo, 0x00000000);
397 BEGIN_RING(evo, 0, 0x0094, 1);
398 OUT_RING (evo, 0x00000000);
399 BEGIN_RING(evo, 0, 0x00c0, 1);
400 OUT_RING (evo, 0x00000000);
401 BEGIN_RING(evo, 0, 0x0080, 1);
402 OUT_RING (evo, 0x00000000);
403 FIRE_RING (evo);
404}
405
406int
407nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
408 struct nouveau_channel *chan)
409{
410 struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
411 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
412 struct nv50_display *disp = nv50_display(crtc->dev);
413 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
414 struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index];
415 struct nouveau_channel *evo = dispc->sync;
416 int ret;
417
Ben Skeggsf66b3d52011-06-16 14:40:27 +1000418 ret = RING_SPACE(evo, chan ? 25 : 27);
Ben Skeggscdccc702011-02-07 13:29:23 +1000419 if (unlikely(ret))
420 return ret;
421
422 /* synchronise with the rendering channel, if necessary */
423 if (likely(chan)) {
Ben Skeggscdccc702011-02-07 13:29:23 +1000424 ret = RING_SPACE(chan, 10);
425 if (ret) {
426 WIND_RING(evo);
427 return ret;
428 }
429
430 if (dev_priv->chipset < 0xc0) {
431 BEGIN_RING(chan, NvSubSw, 0x0060, 2);
432 OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
433 OUT_RING (chan, dispc->sem.offset);
434 BEGIN_RING(chan, NvSubSw, 0x006c, 1);
435 OUT_RING (chan, 0xf00d0000 | dispc->sem.value);
436 BEGIN_RING(chan, NvSubSw, 0x0064, 2);
437 OUT_RING (chan, dispc->sem.offset ^ 0x10);
438 OUT_RING (chan, 0x74b1e000);
439 BEGIN_RING(chan, NvSubSw, 0x0060, 1);
440 if (dev_priv->chipset < 0x84)
441 OUT_RING (chan, NvSema);
442 else
443 OUT_RING (chan, chan->vram_handle);
444 } else {
Ben Skeggs3d483d52011-06-07 15:43:31 +1000445 u64 offset = chan->dispc_vma[nv_crtc->index].offset;
446 offset += dispc->sem.offset;
Ben Skeggscdccc702011-02-07 13:29:23 +1000447 BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
448 OUT_RING (chan, upper_32_bits(offset));
449 OUT_RING (chan, lower_32_bits(offset));
450 OUT_RING (chan, 0xf00d0000 | dispc->sem.value);
451 OUT_RING (chan, 0x1002);
452 BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4);
453 OUT_RING (chan, upper_32_bits(offset));
454 OUT_RING (chan, lower_32_bits(offset ^ 0x10));
455 OUT_RING (chan, 0x74b1e000);
456 OUT_RING (chan, 0x1001);
457 }
458 FIRE_RING (chan);
459 } else {
460 nouveau_bo_wr32(dispc->sem.bo, dispc->sem.offset / 4,
461 0xf00d0000 | dispc->sem.value);
462 }
463
464 /* queue the flip on the crtc's "display sync" channel */
465 BEGIN_RING(evo, 0, 0x0100, 1);
466 OUT_RING (evo, 0xfffe0000);
Ben Skeggsf66b3d52011-06-16 14:40:27 +1000467 if (chan) {
468 BEGIN_RING(evo, 0, 0x0084, 1);
469 OUT_RING (evo, 0x00000100);
470 } else {
471 BEGIN_RING(evo, 0, 0x0084, 1);
472 OUT_RING (evo, 0x00000010);
473 /* allows gamma somehow, PDISP will bitch at you if
474 * you don't wait for vblank before changing this..
475 */
476 BEGIN_RING(evo, 0, 0x00e0, 1);
477 OUT_RING (evo, 0x40000000);
478 }
479 BEGIN_RING(evo, 0, 0x0088, 4);
Ben Skeggscdccc702011-02-07 13:29:23 +1000480 OUT_RING (evo, dispc->sem.offset);
481 OUT_RING (evo, 0xf00d0000 | dispc->sem.value);
482 OUT_RING (evo, 0x74b1e000);
483 OUT_RING (evo, NvEvoSync);
484 BEGIN_RING(evo, 0, 0x00a0, 2);
485 OUT_RING (evo, 0x00000000);
486 OUT_RING (evo, 0x00000000);
487 BEGIN_RING(evo, 0, 0x00c0, 1);
488 OUT_RING (evo, nv_fb->r_dma);
489 BEGIN_RING(evo, 0, 0x0110, 2);
490 OUT_RING (evo, 0x00000000);
491 OUT_RING (evo, 0x00000000);
492 BEGIN_RING(evo, 0, 0x0800, 5);
Ben Skeggs180cc302011-06-07 11:24:14 +1000493 OUT_RING (evo, nv_fb->nvbo->bo.offset >> 8);
Ben Skeggscdccc702011-02-07 13:29:23 +1000494 OUT_RING (evo, 0);
495 OUT_RING (evo, (fb->height << 16) | fb->width);
496 OUT_RING (evo, nv_fb->r_pitch);
497 OUT_RING (evo, nv_fb->r_format);
498 BEGIN_RING(evo, 0, 0x0080, 1);
499 OUT_RING (evo, 0x00000000);
500 FIRE_RING (evo);
501
502 dispc->sem.offset ^= 0x10;
503 dispc->sem.value++;
504 return 0;
505}
506
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000507static u16
508nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
509 u32 mc, int pxclk)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000510{
511 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs75c722d2009-12-21 12:16:52 +1000512 struct nouveau_connector *nv_connector = NULL;
513 struct drm_encoder *encoder;
Ben Skeggs04a39c52010-02-24 10:03:05 +1000514 struct nvbios *bios = &dev_priv->vbios;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000515 u32 script = 0, or;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000516
Ben Skeggs75c722d2009-12-21 12:16:52 +1000517 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
518 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
519
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000520 if (nv_encoder->dcb != dcb)
Ben Skeggs75c722d2009-12-21 12:16:52 +1000521 continue;
522
523 nv_connector = nouveau_encoder_connector_get(nv_encoder);
524 break;
525 }
526
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000527 or = ffs(dcb->or) - 1;
528 switch (dcb->type) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000529 case OUTPUT_LVDS:
530 script = (mc >> 8) & 0xf;
Ben Skeggs04a39c52010-02-24 10:03:05 +1000531 if (bios->fp_no_ddc) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000532 if (bios->fp.dual_link)
533 script |= 0x0100;
534 if (bios->fp.if_is_24bit)
535 script |= 0x0200;
536 } else {
Ben Skeggsb23b9e72011-04-18 10:49:03 +1000537 /* determine number of lvds links */
538 if (nv_connector && nv_connector->edid &&
539 nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
540 /* http://www.spwg.org */
541 if (((u8 *)nv_connector->edid)[121] == 2)
542 script |= 0x0100;
543 } else
Ben Skeggs6ee73862009-12-11 19:24:15 +1000544 if (pxclk >= bios->fp.duallink_transition_clk) {
545 script |= 0x0100;
Ben Skeggsb23b9e72011-04-18 10:49:03 +1000546 }
547
548 /* determine panel depth */
549 if (script & 0x0100) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000550 if (bios->fp.strapless_is_24bit & 2)
551 script |= 0x0200;
Ben Skeggsb23b9e72011-04-18 10:49:03 +1000552 } else {
553 if (bios->fp.strapless_is_24bit & 1)
554 script |= 0x0200;
555 }
Ben Skeggs75c722d2009-12-21 12:16:52 +1000556
557 if (nv_connector && nv_connector->edid &&
558 (nv_connector->edid->revision >= 4) &&
559 (nv_connector->edid->input & 0x70) >= 0x20)
560 script |= 0x0200;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000561 }
562
563 if (nouveau_uscript_lvds >= 0) {
564 NV_INFO(dev, "override script 0x%04x with 0x%04x "
565 "for output LVDS-%d\n", script,
566 nouveau_uscript_lvds, or);
567 script = nouveau_uscript_lvds;
568 }
569 break;
570 case OUTPUT_TMDS:
571 script = (mc >> 8) & 0xf;
572 if (pxclk >= 165000)
573 script |= 0x0100;
574
575 if (nouveau_uscript_tmds >= 0) {
576 NV_INFO(dev, "override script 0x%04x with 0x%04x "
577 "for output TMDS-%d\n", script,
578 nouveau_uscript_tmds, or);
579 script = nouveau_uscript_tmds;
580 }
581 break;
582 case OUTPUT_DP:
583 script = (mc >> 8) & 0xf;
584 break;
585 case OUTPUT_ANALOG:
586 script = 0xff;
587 break;
588 default:
589 NV_ERROR(dev, "modeset on unsupported output type!\n");
590 break;
591 }
592
593 return script;
594}
595
596static void
597nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
598{
599 struct drm_nouveau_private *dev_priv = dev->dev_private;
Francisco Jerez042206c2010-10-21 18:19:29 +0200600 struct nouveau_channel *chan, *tmp;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000601
Francisco Jerez042206c2010-10-21 18:19:29 +0200602 list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting,
603 nvsw.vbl_wait) {
Francisco Jerez1f6d2de2010-10-24 14:15:58 +0200604 if (chan->nvsw.vblsem_head != crtc)
605 continue;
606
Ben Skeggs6ee73862009-12-11 19:24:15 +1000607 nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset,
608 chan->nvsw.vblsem_rval);
609 list_del(&chan->nvsw.vbl_wait);
Francisco Jerez042206c2010-10-21 18:19:29 +0200610 drm_vblank_put(dev, crtc);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000611 }
Francisco Jerez042206c2010-10-21 18:19:29 +0200612
613 drm_handle_vblank(dev, crtc);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000614}
615
616static void
617nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
618{
Ben Skeggs6ee73862009-12-11 19:24:15 +1000619 if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0)
620 nv50_display_vblank_crtc_handler(dev, 0);
621
622 if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1)
623 nv50_display_vblank_crtc_handler(dev, 1);
624
Francisco Jerez042206c2010-10-21 18:19:29 +0200625 nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_VBLANK_CRTC);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000626}
627
628static void
629nv50_display_unk10_handler(struct drm_device *dev)
630{
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000631 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsef8389a2011-02-01 10:07:32 +1000632 struct nv50_display *disp = nv50_display(dev);
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000633 u32 unk30 = nv_rd32(dev, 0x610030), mc;
Ben Skeggsa55b68e2011-11-09 15:30:08 +1000634 int i, crtc, or = 0, type = OUTPUT_ANY;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000635
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000636 NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000637 disp->irq.dcb = NULL;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000638
639 nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8);
640
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000641 /* Determine which CRTC we're dealing with, only 1 ever will be
642 * signalled at the same time with the current nouveau code.
643 */
644 crtc = ffs((unk30 & 0x00000060) >> 5) - 1;
645 if (crtc < 0)
646 goto ack;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000647
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000648 /* Nothing needs to be done for the encoder */
649 crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
650 if (crtc < 0)
651 goto ack;
652
653 /* Find which encoder was connected to the CRTC */
654 for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
655 mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
656 NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
657 if (!(mc & (1 << crtc)))
658 continue;
659
660 switch ((mc & 0x00000f00) >> 8) {
661 case 0: type = OUTPUT_ANALOG; break;
662 case 1: type = OUTPUT_TV; break;
663 default:
664 NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
665 goto ack;
666 }
667
668 or = i;
669 }
670
Ben Skeggs8597a1b2010-09-06 11:39:25 +1000671 for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000672 if (dev_priv->chipset < 0x90 ||
673 dev_priv->chipset == 0x92 ||
674 dev_priv->chipset == 0xa0)
675 mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
676 else
677 mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
678
679 NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
680 if (!(mc & (1 << crtc)))
681 continue;
682
683 switch ((mc & 0x00000f00) >> 8) {
684 case 0: type = OUTPUT_LVDS; break;
685 case 1: type = OUTPUT_TMDS; break;
686 case 2: type = OUTPUT_TMDS; break;
687 case 5: type = OUTPUT_TMDS; break;
688 case 8: type = OUTPUT_DP; break;
689 case 9: type = OUTPUT_DP; break;
690 default:
691 NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
692 goto ack;
693 }
694
695 or = i;
696 }
697
698 /* There was no encoder to disable */
699 if (type == OUTPUT_ANY)
700 goto ack;
701
702 /* Disable the encoder */
703 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
704 struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
705
706 if (dcb->type == type && (dcb->or & (1 << or))) {
Ben Skeggs02e4f582011-07-06 21:21:42 +1000707 nouveau_bios_run_display_table(dev, 0, -1, dcb, -1);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000708 disp->irq.dcb = dcb;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000709 goto ack;
710 }
711 }
712
713 NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000714ack:
715 nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10);
716 nv_wr32(dev, 0x610030, 0x80000000);
717}
718
719static void
720nv50_display_unk20_handler(struct drm_device *dev)
721{
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000722 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsef8389a2011-02-01 10:07:32 +1000723 struct nv50_display *disp = nv50_display(dev);
Ben Skeggsea5f2782011-01-31 08:26:04 +1000724 u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc = 0;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000725 struct dcb_entry *dcb;
Ben Skeggsa55b68e2011-11-09 15:30:08 +1000726 int i, crtc, or = 0, type = OUTPUT_ANY;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000727
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000728 NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000729 dcb = disp->irq.dcb;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000730 if (dcb) {
Ben Skeggs02e4f582011-07-06 21:21:42 +1000731 nouveau_bios_run_display_table(dev, 0, -2, dcb, -1);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000732 disp->irq.dcb = NULL;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000733 }
734
735 /* CRTC clock change requested? */
736 crtc = ffs((unk30 & 0x00000600) >> 9) - 1;
737 if (crtc >= 0) {
738 pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK));
739 pclk &= 0x003fffff;
Ben Skeggsb98e3f52011-10-14 16:13:10 +1000740 if (pclk)
741 nv50_crtc_set_clock(dev, crtc, pclk);
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000742
743 tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc));
744 tmp &= ~0x000000f;
745 nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp);
746 }
747
748 /* Nothing needs to be done for the encoder */
749 crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
750 if (crtc < 0)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000751 goto ack;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000752 pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000753
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000754 /* Find which encoder is connected to the CRTC */
755 for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
756 mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i));
757 NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
758 if (!(mc & (1 << crtc)))
759 continue;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000760
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000761 switch ((mc & 0x00000f00) >> 8) {
762 case 0: type = OUTPUT_ANALOG; break;
763 case 1: type = OUTPUT_TV; break;
764 default:
765 NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
766 goto ack;
767 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000768
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000769 or = i;
770 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000771
Ben Skeggs8597a1b2010-09-06 11:39:25 +1000772 for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000773 if (dev_priv->chipset < 0x90 ||
774 dev_priv->chipset == 0x92 ||
775 dev_priv->chipset == 0xa0)
776 mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i));
777 else
778 mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i));
Ben Skeggs6ee73862009-12-11 19:24:15 +1000779
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000780 NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
781 if (!(mc & (1 << crtc)))
782 continue;
Ben Skeggsafa3b4c2010-04-23 08:21:48 +1000783
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000784 switch ((mc & 0x00000f00) >> 8) {
785 case 0: type = OUTPUT_LVDS; break;
786 case 1: type = OUTPUT_TMDS; break;
787 case 2: type = OUTPUT_TMDS; break;
788 case 5: type = OUTPUT_TMDS; break;
789 case 8: type = OUTPUT_DP; break;
790 case 9: type = OUTPUT_DP; break;
791 default:
792 NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
793 goto ack;
794 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000795
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000796 or = i;
797 }
798
799 if (type == OUTPUT_ANY)
800 goto ack;
801
802 /* Enable the encoder */
803 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
804 dcb = &dev_priv->vbios.dcb.entry[i];
805 if (dcb->type == type && (dcb->or & (1 << or)))
806 break;
807 }
808
809 if (i == dev_priv->vbios.dcb.entries) {
810 NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
811 goto ack;
812 }
813
814 script = nv50_display_script_select(dev, dcb, mc, pclk);
Ben Skeggs02e4f582011-07-06 21:21:42 +1000815 nouveau_bios_run_display_table(dev, script, pclk, dcb, -1);
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000816
Ben Skeggs46959b72011-07-01 15:51:49 +1000817 if (type == OUTPUT_DP) {
818 int link = !(dcb->dpconf.sor.link & 1);
819 if ((mc & 0x000f0000) == 0x00020000)
820 nouveau_dp_tu_update(dev, or, link, pclk, 18);
821 else
822 nouveau_dp_tu_update(dev, or, link, pclk, 24);
823 }
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000824
825 if (dcb->type != OUTPUT_ANALOG) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000826 tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
827 tmp &= ~0x00000f0f;
828 if (script & 0x0100)
829 tmp |= 0x00000101;
830 nv_wr32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or), tmp);
831 } else {
832 nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
833 }
834
Ben Skeggsef8389a2011-02-01 10:07:32 +1000835 disp->irq.dcb = dcb;
836 disp->irq.pclk = pclk;
837 disp->irq.script = script;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000838
Ben Skeggs6ee73862009-12-11 19:24:15 +1000839ack:
840 nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20);
841 nv_wr32(dev, 0x610030, 0x80000000);
842}
843
Ben Skeggs271f29e2010-07-09 10:37:42 +1000844/* If programming a TMDS output on a SOR that can also be configured for
845 * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
846 *
847 * It looks like the VBIOS TMDS scripts make an attempt at this, however,
848 * the VBIOS scripts on at least one board I have only switch it off on
849 * link 0, causing a blank display if the output has previously been
850 * programmed for DisplayPort.
851 */
852static void
853nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb)
854{
855 int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
856 struct drm_encoder *encoder;
857 u32 tmp;
858
859 if (dcb->type != OUTPUT_TMDS)
860 return;
861
862 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
863 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
864
865 if (nv_encoder->dcb->type == OUTPUT_DP &&
866 nv_encoder->dcb->or & (1 << or)) {
867 tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
868 tmp &= ~NV50_SOR_DP_CTRL_ENABLED;
869 nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
870 break;
871 }
872 }
873}
874
Ben Skeggs6ee73862009-12-11 19:24:15 +1000875static void
876nv50_display_unk40_handler(struct drm_device *dev)
877{
Ben Skeggsef8389a2011-02-01 10:07:32 +1000878 struct nv50_display *disp = nv50_display(dev);
879 struct dcb_entry *dcb = disp->irq.dcb;
880 u16 script = disp->irq.script;
881 u32 unk30 = nv_rd32(dev, 0x610030), pclk = disp->irq.pclk;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000882
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000883 NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
Ben Skeggsef8389a2011-02-01 10:07:32 +1000884 disp->irq.dcb = NULL;
Ben Skeggs87c0e0e2010-07-06 08:54:34 +1000885 if (!dcb)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000886 goto ack;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000887
Ben Skeggs02e4f582011-07-06 21:21:42 +1000888 nouveau_bios_run_display_table(dev, script, -pclk, dcb, -1);
Ben Skeggs271f29e2010-07-09 10:37:42 +1000889 nv50_display_unk40_dp_set_tmds(dev, dcb);
890
Ben Skeggs6ee73862009-12-11 19:24:15 +1000891ack:
892 nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40);
893 nv_wr32(dev, 0x610030, 0x80000000);
894 nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) | 8);
895}
896
Ben Skeggsf13e4352011-02-03 20:06:14 +1000897static void
898nv50_display_bh(unsigned long data)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000899{
Ben Skeggsf13e4352011-02-03 20:06:14 +1000900 struct drm_device *dev = (struct drm_device *)data;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000901
902 for (;;) {
903 uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
904 uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
905
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100906 NV_DEBUG_KMS(dev, "PDISPLAY_INTR_BH 0x%08x 0x%08x\n", intr0, intr1);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000907
908 if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK10)
909 nv50_display_unk10_handler(dev);
910 else
911 if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK20)
912 nv50_display_unk20_handler(dev);
913 else
914 if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK40)
915 nv50_display_unk40_handler(dev);
916 else
917 break;
918 }
919
920 nv_wr32(dev, NV03_PMC_INTR_EN_0, 1);
921}
922
923static void
924nv50_display_error_handler(struct drm_device *dev)
925{
Ben Skeggs97e20002010-10-20 14:23:29 +1000926 u32 channels = (nv_rd32(dev, NV50_PDISPLAY_INTR_0) & 0x001f0000) >> 16;
927 u32 addr, data;
928 int chid;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000929
Ben Skeggs97e20002010-10-20 14:23:29 +1000930 for (chid = 0; chid < 5; chid++) {
931 if (!(channels & (1 << chid)))
932 continue;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000933
Ben Skeggs97e20002010-10-20 14:23:29 +1000934 nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000 << chid);
935 addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid));
936 data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA(chid));
937 NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x "
938 "(0x%04x 0x%02x)\n", chid,
939 addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000940
Ben Skeggs97e20002010-10-20 14:23:29 +1000941 nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid), 0x90000000);
942 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000943}
944
Ben Skeggs19b7fc72010-11-03 10:27:27 +1000945static void
946nv50_display_isr(struct drm_device *dev)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000947{
Ben Skeggsf13e4352011-02-03 20:06:14 +1000948 struct nv50_display *disp = nv50_display(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000949 uint32_t delayed = 0;
950
Ben Skeggs6ee73862009-12-11 19:24:15 +1000951 while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
952 uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
953 uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
954 uint32_t clock;
955
Maarten Maathuisef2bb502009-12-13 16:53:12 +0100956 NV_DEBUG_KMS(dev, "PDISPLAY_INTR 0x%08x 0x%08x\n", intr0, intr1);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000957
958 if (!intr0 && !(intr1 & ~delayed))
959 break;
960
Ben Skeggs97e20002010-10-20 14:23:29 +1000961 if (intr0 & 0x001f0000) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000962 nv50_display_error_handler(dev);
Ben Skeggs97e20002010-10-20 14:23:29 +1000963 intr0 &= ~0x001f0000;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000964 }
965
966 if (intr1 & NV50_PDISPLAY_INTR_1_VBLANK_CRTC) {
967 nv50_display_vblank_handler(dev, intr1);
968 intr1 &= ~NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
969 }
970
971 clock = (intr1 & (NV50_PDISPLAY_INTR_1_CLK_UNK10 |
972 NV50_PDISPLAY_INTR_1_CLK_UNK20 |
973 NV50_PDISPLAY_INTR_1_CLK_UNK40));
974 if (clock) {
975 nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
Ben Skeggsf13e4352011-02-03 20:06:14 +1000976 tasklet_schedule(&disp->tasklet);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000977 delayed |= clock;
978 intr1 &= ~clock;
979 }
980
981 if (intr0) {
982 NV_ERROR(dev, "unknown PDISPLAY_INTR_0: 0x%08x\n", intr0);
983 nv_wr32(dev, NV50_PDISPLAY_INTR_0, intr0);
984 }
985
986 if (intr1) {
987 NV_ERROR(dev,
988 "unknown PDISPLAY_INTR_1: 0x%08x\n", intr1);
989 nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr1);
990 }
991 }
992}