blob: dcfe6192e5c47c5512b7f9047e0c949f028eca3c [file] [log] [blame]
Ben Skeggs26f6d882011-07-04 16:25:18 +10001/*
2 * Copyright 2011 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
Ben Skeggs51beb422011-07-05 10:33:08 +100025#include <linux/dma-mapping.h>
Ben Skeggs83fc0832011-07-05 13:08:40 +100026
Ben Skeggs26f6d882011-07-04 16:25:18 +100027#include "drmP.h"
Ben Skeggs83fc0832011-07-05 13:08:40 +100028#include "drm_crtc_helper.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100029
30#include "nouveau_drv.h"
31#include "nouveau_connector.h"
32#include "nouveau_encoder.h"
33#include "nouveau_crtc.h"
Ben Skeggs37b034a2011-07-08 14:43:19 +100034#include "nouveau_dma.h"
Ben Skeggs438d99e2011-07-05 16:48:06 +100035#include "nouveau_fb.h"
Ben Skeggs3a89cd02011-07-07 10:47:10 +100036#include "nv50_display.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100037
38struct nvd0_display {
39 struct nouveau_gpuobj *mem;
Ben Skeggs51beb422011-07-05 10:33:08 +100040 struct {
41 dma_addr_t handle;
42 u32 *ptr;
43 } evo[1];
Ben Skeggsf20ce962011-07-08 13:17:01 +100044
45 struct tasklet_struct tasklet;
Ben Skeggsee417792011-07-08 14:34:45 +100046 u32 modeset;
Ben Skeggs26f6d882011-07-04 16:25:18 +100047};
48
49static struct nvd0_display *
50nvd0_display(struct drm_device *dev)
51{
52 struct drm_nouveau_private *dev_priv = dev->dev_private;
53 return dev_priv->engine.display.priv;
54}
55
Ben Skeggs37b034a2011-07-08 14:43:19 +100056static inline int
Ben Skeggs51beb422011-07-05 10:33:08 +100057evo_icmd(struct drm_device *dev, int id, u32 mthd, u32 data)
58{
59 int ret = 0;
60 nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000001);
61 nv_wr32(dev, 0x610704 + (id * 0x10), data);
62 nv_mask(dev, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd);
63 if (!nv_wait(dev, 0x610704 + (id * 0x10), 0x80000000, 0x00000000))
64 ret = -EBUSY;
65 nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000000);
66 return ret;
67}
68
69static u32 *
70evo_wait(struct drm_device *dev, int id, int nr)
71{
72 struct nvd0_display *disp = nvd0_display(dev);
73 u32 put = nv_rd32(dev, 0x640000 + (id * 0x1000)) / 4;
74
75 if (put + nr >= (PAGE_SIZE / 4)) {
76 disp->evo[id].ptr[put] = 0x20000000;
77
78 nv_wr32(dev, 0x640000 + (id * 0x1000), 0x00000000);
79 if (!nv_wait(dev, 0x640004 + (id * 0x1000), ~0, 0x00000000)) {
80 NV_ERROR(dev, "evo %d dma stalled\n", id);
81 return NULL;
82 }
83
84 put = 0;
85 }
86
Ben Skeggs27517dd2011-11-11 20:26:44 +100087 if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
88 NV_INFO(dev, "Evo%d: %p START\n", id, disp->evo[id].ptr + put);
89
Ben Skeggs51beb422011-07-05 10:33:08 +100090 return disp->evo[id].ptr + put;
91}
92
93static void
94evo_kick(u32 *push, struct drm_device *dev, int id)
95{
96 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs27517dd2011-11-11 20:26:44 +100097
98 if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO) {
99 u32 curp = nv_rd32(dev, 0x640000 + (id * 0x1000)) >> 2;
100 u32 *cur = disp->evo[id].ptr + curp;
101
102 while (cur < push)
103 NV_INFO(dev, "Evo%d: 0x%08x\n", id, *cur++);
104 NV_INFO(dev, "Evo%d: %p KICK!\n", id, push);
105 }
106
Ben Skeggs51beb422011-07-05 10:33:08 +1000107 nv_wr32(dev, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2);
108}
109
110#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
111#define evo_data(p,d) *((p)++) = (d)
112
Ben Skeggs83fc0832011-07-05 13:08:40 +1000113static struct drm_crtc *
114nvd0_display_crtc_get(struct drm_encoder *encoder)
115{
116 return nouveau_encoder(encoder)->crtc;
117}
118
Ben Skeggs26f6d882011-07-04 16:25:18 +1000119/******************************************************************************
Ben Skeggs438d99e2011-07-05 16:48:06 +1000120 * CRTC
121 *****************************************************************************/
122static int
Ben Skeggs488ff202011-10-17 10:38:10 +1000123nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000124{
125 struct drm_device *dev = nv_crtc->base.dev;
Ben Skeggsde691852011-10-17 12:23:41 +1000126 struct nouveau_connector *nv_connector;
127 struct drm_connector *connector;
128 u32 *push, mode = 0x00;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000129
Ben Skeggs488ff202011-10-17 10:38:10 +1000130 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsde691852011-10-17 12:23:41 +1000131 connector = &nv_connector->base;
132 if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
133 if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
134 mode = DITHERING_MODE_DYNAMIC2X2;
135 } else {
136 mode = nv_connector->dithering_mode;
137 }
138
139 if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) {
140 if (connector->display_info.bpc >= 8)
141 mode |= DITHERING_DEPTH_8BPC;
142 } else {
143 mode |= nv_connector->dithering_depth;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000144 }
145
146 push = evo_wait(dev, 0, 4);
147 if (push) {
148 evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1);
149 evo_data(push, mode);
150 if (update) {
151 evo_mthd(push, 0x0080, 1);
152 evo_data(push, 0x00000000);
153 }
154 evo_kick(push, dev, 0);
155 }
156
157 return 0;
158}
159
160static int
Ben Skeggs488ff202011-10-17 10:38:10 +1000161nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000162{
Ben Skeggs92854622011-11-11 23:49:06 +1000163 struct drm_display_mode *omode, *umode = &nv_crtc->base.mode;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000164 struct drm_device *dev = nv_crtc->base.dev;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000165 struct nouveau_connector *nv_connector;
Ben Skeggs92854622011-11-11 23:49:06 +1000166 int mode = DRM_MODE_SCALE_NONE;
167 u32 oX, oY, *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000168
Ben Skeggs92854622011-11-11 23:49:06 +1000169 /* start off at the resolution we programmed the crtc for, this
170 * effectively handles NONE/FULL scaling
171 */
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000172 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggs92854622011-11-11 23:49:06 +1000173 if (nv_connector && nv_connector->native_mode)
174 mode = nv_connector->scaling_mode;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000175
Ben Skeggs92854622011-11-11 23:49:06 +1000176 if (mode != DRM_MODE_SCALE_NONE)
177 omode = nv_connector->native_mode;
178 else
179 omode = umode;
180
181 oX = omode->hdisplay;
182 oY = omode->vdisplay;
183 if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
184 oY *= 2;
185
186 /* add overscan compensation if necessary, will keep the aspect
187 * ratio the same as the backend mode unless overridden by the
188 * user setting both hborder and vborder properties.
189 */
190 if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
191 (nv_connector->underscan == UNDERSCAN_AUTO &&
192 nv_connector->edid &&
193 drm_detect_hdmi_monitor(nv_connector->edid)))) {
194 u32 bX = nv_connector->underscan_hborder;
195 u32 bY = nv_connector->underscan_vborder;
196 u32 aspect = (oY << 19) / oX;
197
198 if (bX) {
199 oX -= (bX * 2);
200 if (bY) oY -= (bY * 2);
201 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
202 } else {
203 oX -= (oX >> 4) + 32;
204 if (bY) oY -= (bY * 2);
205 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000206 }
207 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000208
Ben Skeggs92854622011-11-11 23:49:06 +1000209 /* handle CENTER/ASPECT scaling, taking into account the areas
210 * removed already for overscan compensation
211 */
212 switch (mode) {
213 case DRM_MODE_SCALE_CENTER:
214 oX = min((u32)umode->hdisplay, oX);
215 oY = min((u32)umode->vdisplay, oY);
216 /* fall-through */
217 case DRM_MODE_SCALE_ASPECT:
218 if (oY < oX) {
219 u32 aspect = (umode->hdisplay << 19) / umode->vdisplay;
220 oX = ((oY * aspect) + (aspect / 2)) >> 19;
221 } else {
222 u32 aspect = (umode->vdisplay << 19) / umode->hdisplay;
223 oY = ((oX * aspect) + (aspect / 2)) >> 19;
224 }
225 break;
226 default:
227 break;
228 }
229
Ben Skeggs438d99e2011-07-05 16:48:06 +1000230 push = evo_wait(dev, 0, 16);
231 if (push) {
232 evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
Ben Skeggs92854622011-11-11 23:49:06 +1000233 evo_data(push, (oY << 16) | oX);
234 evo_data(push, (oY << 16) | oX);
235 evo_data(push, (oY << 16) | oX);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000236 evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
237 evo_data(push, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000238 evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
Ben Skeggs92854622011-11-11 23:49:06 +1000239 evo_data(push, (umode->vdisplay << 16) | umode->hdisplay);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000240 if (update) {
241 evo_mthd(push, 0x0080, 1);
242 evo_data(push, 0x00000000);
243 }
244 evo_kick(push, dev, 0);
245 }
246
247 return 0;
248}
249
250static int
251nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
252 int x, int y, bool update)
253{
254 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
255 u32 *push;
256
Ben Skeggs438d99e2011-07-05 16:48:06 +1000257 push = evo_wait(fb->dev, 0, 16);
258 if (push) {
259 evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1);
260 evo_data(push, nvfb->nvbo->bo.offset >> 8);
261 evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4);
262 evo_data(push, (fb->height << 16) | fb->width);
263 evo_data(push, nvfb->r_pitch);
264 evo_data(push, nvfb->r_format);
Ben Skeggsc0cc92a2011-07-06 11:40:45 +1000265 evo_data(push, nvfb->r_dma);
Ben Skeggsc6f2f712011-07-08 12:11:58 +1000266 evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1);
267 evo_data(push, (y << 16) | x);
Ben Skeggsa46232e2011-07-07 15:23:48 +1000268 if (update) {
269 evo_mthd(push, 0x0080, 1);
270 evo_data(push, 0x00000000);
271 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000272 evo_kick(push, fb->dev, 0);
273 }
274
Ben Skeggsc0cc92a2011-07-06 11:40:45 +1000275 nv_crtc->fb.tile_flags = nvfb->r_dma;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000276 return 0;
277}
278
279static void
280nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update)
281{
282 struct drm_device *dev = nv_crtc->base.dev;
283 u32 *push = evo_wait(dev, 0, 16);
284 if (push) {
285 if (show) {
286 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
287 evo_data(push, 0x85000000);
288 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
289 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +1000290 evo_data(push, NvEvoVRAM);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000291 } else {
292 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1);
293 evo_data(push, 0x05000000);
294 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
295 evo_data(push, 0x00000000);
296 }
297
298 if (update) {
299 evo_mthd(push, 0x0080, 1);
300 evo_data(push, 0x00000000);
301 }
302
303 evo_kick(push, dev, 0);
304 }
305}
306
307static void
308nvd0_crtc_dpms(struct drm_crtc *crtc, int mode)
309{
310}
311
312static void
313nvd0_crtc_prepare(struct drm_crtc *crtc)
314{
315 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
316 u32 *push;
317
318 push = evo_wait(crtc->dev, 0, 2);
319 if (push) {
320 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
321 evo_data(push, 0x00000000);
322 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1);
323 evo_data(push, 0x03000000);
324 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
325 evo_data(push, 0x00000000);
326 evo_kick(push, crtc->dev, 0);
327 }
328
329 nvd0_crtc_cursor_show(nv_crtc, false, false);
330}
331
332static void
333nvd0_crtc_commit(struct drm_crtc *crtc)
334{
335 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
336 u32 *push;
337
338 push = evo_wait(crtc->dev, 0, 32);
339 if (push) {
340 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
341 evo_data(push, nv_crtc->fb.tile_flags);
342 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4);
343 evo_data(push, 0x83000000);
344 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
345 evo_data(push, 0x00000000);
346 evo_data(push, 0x00000000);
347 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +1000348 evo_data(push, NvEvoVRAM);
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000349 evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1);
350 evo_data(push, 0xffffff00);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000351 evo_kick(push, crtc->dev, 0);
352 }
353
354 nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true);
355}
356
357static bool
358nvd0_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
359 struct drm_display_mode *adjusted_mode)
360{
361 return true;
362}
363
364static int
365nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
366{
367 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
368 int ret;
369
370 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
371 if (ret)
372 return ret;
373
374 if (old_fb) {
375 nvfb = nouveau_framebuffer(old_fb);
376 nouveau_bo_unpin(nvfb->nvbo);
377 }
378
379 return 0;
380}
381
382static int
383nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
384 struct drm_display_mode *mode, int x, int y,
385 struct drm_framebuffer *old_fb)
386{
387 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
388 struct nouveau_connector *nv_connector;
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000389 u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
390 u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
391 u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
392 u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
393 u32 vblan2e = 0, vblan2s = 1;
394 u32 magic = 0x31ec6000;
Ben Skeggs629c1b92011-07-08 09:43:20 +1000395 u32 syncs, *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000396 int ret;
397
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000398 hactive = mode->htotal;
399 hsynce = mode->hsync_end - mode->hsync_start - 1;
400 hbackp = mode->htotal - mode->hsync_end;
401 hblanke = hsynce + hbackp;
402 hfrontp = mode->hsync_start - mode->hdisplay;
403 hblanks = mode->htotal - hfrontp - 1;
404
405 vactive = mode->vtotal * vscan / ilace;
406 vsynce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
407 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
408 vblanke = vsynce + vbackp;
409 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
410 vblanks = vactive - vfrontp - 1;
411 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
412 vblan2e = vactive + vsynce + vbackp;
413 vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
414 vactive = (vactive * 2) + 1;
415 magic |= 0x00000001;
416 }
417
Ben Skeggs629c1b92011-07-08 09:43:20 +1000418 syncs = 0x00000001;
419 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
420 syncs |= 0x00000008;
421 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
422 syncs |= 0x00000010;
423
Ben Skeggs438d99e2011-07-05 16:48:06 +1000424 ret = nvd0_crtc_swap_fbs(crtc, old_fb);
425 if (ret)
426 return ret;
427
428 push = evo_wait(crtc->dev, 0, 64);
429 if (push) {
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000430 evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 6);
Ben Skeggs629c1b92011-07-08 09:43:20 +1000431 evo_data(push, 0x00000000);
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000432 evo_data(push, (vactive << 16) | hactive);
433 evo_data(push, ( vsynce << 16) | hsynce);
434 evo_data(push, (vblanke << 16) | hblanke);
435 evo_data(push, (vblanks << 16) | hblanks);
436 evo_data(push, (vblan2e << 16) | vblan2s);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000437 evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1);
438 evo_data(push, 0x00000000); /* ??? */
439 evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3);
440 evo_data(push, mode->clock * 1000);
441 evo_data(push, 0x00200000); /* ??? */
442 evo_data(push, mode->clock * 1000);
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000443 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
Ben Skeggs629c1b92011-07-08 09:43:20 +1000444 evo_data(push, syncs);
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000445 evo_data(push, magic);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000446 evo_kick(push, crtc->dev, 0);
447 }
448
449 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggs488ff202011-10-17 10:38:10 +1000450 nvd0_crtc_set_dither(nv_crtc, false);
451 nvd0_crtc_set_scale(nv_crtc, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000452 nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
453 return 0;
454}
455
456static int
457nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
458 struct drm_framebuffer *old_fb)
459{
460 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
461 int ret;
462
Ben Skeggs84e2ad82011-08-26 09:40:39 +1000463 if (!crtc->fb) {
464 NV_DEBUG_KMS(crtc->dev, "No FB bound\n");
465 return 0;
466 }
467
Ben Skeggs438d99e2011-07-05 16:48:06 +1000468 ret = nvd0_crtc_swap_fbs(crtc, old_fb);
469 if (ret)
470 return ret;
471
472 nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
473 return 0;
474}
475
476static int
477nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
478 struct drm_framebuffer *fb, int x, int y,
479 enum mode_set_atomic state)
480{
481 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
482 nvd0_crtc_set_image(nv_crtc, fb, x, y, true);
483 return 0;
484}
485
486static void
487nvd0_crtc_lut_load(struct drm_crtc *crtc)
488{
489 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
490 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
491 int i;
492
493 for (i = 0; i < 256; i++) {
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000494 writew(0x6000 + (nv_crtc->lut.r[i] >> 2), lut + (i * 0x20) + 0);
495 writew(0x6000 + (nv_crtc->lut.g[i] >> 2), lut + (i * 0x20) + 2);
496 writew(0x6000 + (nv_crtc->lut.b[i] >> 2), lut + (i * 0x20) + 4);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000497 }
498}
499
500static int
501nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
502 uint32_t handle, uint32_t width, uint32_t height)
503{
504 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
505 struct drm_device *dev = crtc->dev;
506 struct drm_gem_object *gem;
507 struct nouveau_bo *nvbo;
508 bool visible = (handle != 0);
509 int i, ret = 0;
510
511 if (visible) {
512 if (width != 64 || height != 64)
513 return -EINVAL;
514
515 gem = drm_gem_object_lookup(dev, file_priv, handle);
516 if (unlikely(!gem))
517 return -ENOENT;
518 nvbo = nouveau_gem_object(gem);
519
520 ret = nouveau_bo_map(nvbo);
521 if (ret == 0) {
522 for (i = 0; i < 64 * 64; i++) {
523 u32 v = nouveau_bo_rd32(nvbo, i);
524 nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v);
525 }
526 nouveau_bo_unmap(nvbo);
527 }
528
529 drm_gem_object_unreference_unlocked(gem);
530 }
531
532 if (visible != nv_crtc->cursor.visible) {
533 nvd0_crtc_cursor_show(nv_crtc, visible, true);
534 nv_crtc->cursor.visible = visible;
535 }
536
537 return ret;
538}
539
540static int
541nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
542{
543 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
544 const u32 data = (y << 16) | x;
545
546 nv_wr32(crtc->dev, 0x64d084 + (nv_crtc->index * 0x1000), data);
547 nv_wr32(crtc->dev, 0x64d080 + (nv_crtc->index * 0x1000), 0x00000000);
548 return 0;
549}
550
551static void
552nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
553 uint32_t start, uint32_t size)
554{
555 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
556 u32 end = max(start + size, (u32)256);
557 u32 i;
558
559 for (i = start; i < end; i++) {
560 nv_crtc->lut.r[i] = r[i];
561 nv_crtc->lut.g[i] = g[i];
562 nv_crtc->lut.b[i] = b[i];
563 }
564
565 nvd0_crtc_lut_load(crtc);
566}
567
568static void
569nvd0_crtc_destroy(struct drm_crtc *crtc)
570{
571 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
572 nouveau_bo_unmap(nv_crtc->cursor.nvbo);
573 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
574 nouveau_bo_unmap(nv_crtc->lut.nvbo);
575 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
576 drm_crtc_cleanup(crtc);
577 kfree(crtc);
578}
579
580static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = {
581 .dpms = nvd0_crtc_dpms,
582 .prepare = nvd0_crtc_prepare,
583 .commit = nvd0_crtc_commit,
584 .mode_fixup = nvd0_crtc_mode_fixup,
585 .mode_set = nvd0_crtc_mode_set,
586 .mode_set_base = nvd0_crtc_mode_set_base,
587 .mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic,
588 .load_lut = nvd0_crtc_lut_load,
589};
590
591static const struct drm_crtc_funcs nvd0_crtc_func = {
592 .cursor_set = nvd0_crtc_cursor_set,
593 .cursor_move = nvd0_crtc_cursor_move,
594 .gamma_set = nvd0_crtc_gamma_set,
595 .set_config = drm_crtc_helper_set_config,
596 .destroy = nvd0_crtc_destroy,
597};
598
Ben Skeggsc20ab3e2011-08-25 14:09:43 +1000599static void
600nvd0_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
601{
602}
603
604static void
605nvd0_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
606{
607}
608
Ben Skeggs438d99e2011-07-05 16:48:06 +1000609static int
610nvd0_crtc_create(struct drm_device *dev, int index)
611{
612 struct nouveau_crtc *nv_crtc;
613 struct drm_crtc *crtc;
614 int ret, i;
615
616 nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
617 if (!nv_crtc)
618 return -ENOMEM;
619
620 nv_crtc->index = index;
621 nv_crtc->set_dither = nvd0_crtc_set_dither;
622 nv_crtc->set_scale = nvd0_crtc_set_scale;
Ben Skeggsc20ab3e2011-08-25 14:09:43 +1000623 nv_crtc->cursor.set_offset = nvd0_cursor_set_offset;
624 nv_crtc->cursor.set_pos = nvd0_cursor_set_pos;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000625 for (i = 0; i < 256; i++) {
626 nv_crtc->lut.r[i] = i << 8;
627 nv_crtc->lut.g[i] = i << 8;
628 nv_crtc->lut.b[i] = i << 8;
629 }
630
631 crtc = &nv_crtc->base;
632 drm_crtc_init(dev, crtc, &nvd0_crtc_func);
633 drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc);
634 drm_mode_crtc_set_gamma_size(crtc, 256);
635
636 ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
637 0, 0x0000, &nv_crtc->cursor.nvbo);
638 if (!ret) {
639 ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
640 if (!ret)
641 ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
642 if (ret)
643 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
644 }
645
646 if (ret)
647 goto out;
648
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000649 ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
Ben Skeggs438d99e2011-07-05 16:48:06 +1000650 0, 0x0000, &nv_crtc->lut.nvbo);
651 if (!ret) {
652 ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
653 if (!ret)
654 ret = nouveau_bo_map(nv_crtc->lut.nvbo);
655 if (ret)
656 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
657 }
658
659 if (ret)
660 goto out;
661
662 nvd0_crtc_lut_load(crtc);
663
664out:
665 if (ret)
666 nvd0_crtc_destroy(crtc);
667 return ret;
668}
669
670/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +1000671 * DAC
672 *****************************************************************************/
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000673static void
674nvd0_dac_dpms(struct drm_encoder *encoder, int mode)
675{
676 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
677 struct drm_device *dev = encoder->dev;
678 int or = nv_encoder->or;
679 u32 dpms_ctrl;
680
681 dpms_ctrl = 0x80000000;
682 if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF)
683 dpms_ctrl |= 0x00000001;
684 if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF)
685 dpms_ctrl |= 0x00000004;
686
687 nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
688 nv_mask(dev, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl);
689 nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
690}
691
692static bool
693nvd0_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
694 struct drm_display_mode *adjusted_mode)
695{
696 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
697 struct nouveau_connector *nv_connector;
698
699 nv_connector = nouveau_encoder_connector_get(nv_encoder);
700 if (nv_connector && nv_connector->native_mode) {
701 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
702 int id = adjusted_mode->base.id;
703 *adjusted_mode = *nv_connector->native_mode;
704 adjusted_mode->base.id = id;
705 }
706 }
707
708 return true;
709}
710
711static void
712nvd0_dac_prepare(struct drm_encoder *encoder)
713{
714}
715
716static void
717nvd0_dac_commit(struct drm_encoder *encoder)
718{
719}
720
721static void
722nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
723 struct drm_display_mode *adjusted_mode)
724{
725 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
726 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
727 u32 *push;
728
729 nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON);
730
Ben Skeggsff8ff502011-07-08 11:53:37 +1000731 push = evo_wait(encoder->dev, 0, 4);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000732 if (push) {
Ben Skeggsff8ff502011-07-08 11:53:37 +1000733 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000734 evo_data(push, 1 << nv_crtc->index);
Ben Skeggsff8ff502011-07-08 11:53:37 +1000735 evo_data(push, 0x00ff);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000736 evo_kick(push, encoder->dev, 0);
737 }
738
739 nv_encoder->crtc = encoder->crtc;
740}
741
742static void
743nvd0_dac_disconnect(struct drm_encoder *encoder)
744{
745 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
746 struct drm_device *dev = encoder->dev;
747 u32 *push;
748
749 if (nv_encoder->crtc) {
750 nvd0_crtc_prepare(nv_encoder->crtc);
751
752 push = evo_wait(dev, 0, 4);
753 if (push) {
754 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 1);
755 evo_data(push, 0x00000000);
756 evo_mthd(push, 0x0080, 1);
757 evo_data(push, 0x00000000);
758 evo_kick(push, dev, 0);
759 }
760
761 nv_encoder->crtc = NULL;
762 }
763}
764
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000765static enum drm_connector_status
766nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
767{
Ben Skeggsb6819932011-07-08 11:14:50 +1000768 enum drm_connector_status status = connector_status_disconnected;
769 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
770 struct drm_device *dev = encoder->dev;
771 int or = nv_encoder->or;
772 u32 load;
773
774 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00100000);
775 udelay(9500);
776 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x80000000);
777
778 load = nv_rd32(dev, 0x61a00c + (or * 0x800));
779 if ((load & 0x38000000) == 0x38000000)
780 status = connector_status_connected;
781
782 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00000000);
783 return status;
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000784}
785
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000786static void
787nvd0_dac_destroy(struct drm_encoder *encoder)
788{
789 drm_encoder_cleanup(encoder);
790 kfree(encoder);
791}
792
793static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = {
794 .dpms = nvd0_dac_dpms,
795 .mode_fixup = nvd0_dac_mode_fixup,
796 .prepare = nvd0_dac_prepare,
797 .commit = nvd0_dac_commit,
798 .mode_set = nvd0_dac_mode_set,
799 .disable = nvd0_dac_disconnect,
800 .get_crtc = nvd0_display_crtc_get,
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000801 .detect = nvd0_dac_detect
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000802};
803
804static const struct drm_encoder_funcs nvd0_dac_func = {
805 .destroy = nvd0_dac_destroy,
806};
807
808static int
809nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe)
810{
811 struct drm_device *dev = connector->dev;
812 struct nouveau_encoder *nv_encoder;
813 struct drm_encoder *encoder;
814
815 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
816 if (!nv_encoder)
817 return -ENOMEM;
818 nv_encoder->dcb = dcbe;
819 nv_encoder->or = ffs(dcbe->or) - 1;
820
821 encoder = to_drm_encoder(nv_encoder);
822 encoder->possible_crtcs = dcbe->heads;
823 encoder->possible_clones = 0;
824 drm_encoder_init(dev, encoder, &nvd0_dac_func, DRM_MODE_ENCODER_DAC);
825 drm_encoder_helper_add(encoder, &nvd0_dac_hfunc);
826
827 drm_mode_connector_attach_encoder(connector, encoder);
828 return 0;
829}
Ben Skeggs26f6d882011-07-04 16:25:18 +1000830
831/******************************************************************************
Ben Skeggs78951d22011-11-11 18:13:13 +1000832 * Audio
833 *****************************************************************************/
834static void
835nvd0_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
836{
837 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
838 struct nouveau_connector *nv_connector;
839 struct drm_device *dev = encoder->dev;
840 int i, or = nv_encoder->or * 0x30;
841
842 nv_connector = nouveau_encoder_connector_get(nv_encoder);
843 if (!drm_detect_monitor_audio(nv_connector->edid))
844 return;
845
846 nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000001);
847
848 drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
849 if (nv_connector->base.eld[0]) {
850 u8 *eld = nv_connector->base.eld;
851
852 for (i = 0; i < eld[2] * 4; i++)
853 nv_wr32(dev, 0x10ec00 + or, (i << 8) | eld[i]);
854 for (i = eld[2] * 4; i < 0x60; i++)
855 nv_wr32(dev, 0x10ec00 + or, (i << 8) | 0x00);
856
857 nv_mask(dev, 0x10ec10 + or, 0x80000002, 0x80000002);
858 }
859}
860
861static void
862nvd0_audio_disconnect(struct drm_encoder *encoder)
863{
864 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
865 struct drm_device *dev = encoder->dev;
866 int or = nv_encoder->or * 0x30;
867
868 nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000000);
869}
870
871/******************************************************************************
872 * HDMI
873 *****************************************************************************/
874static void
875nvd0_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
876{
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000877 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
878 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
879 struct nouveau_connector *nv_connector;
880 struct drm_device *dev = encoder->dev;
881 int head = nv_crtc->index * 0x800;
882 u32 rekey = 56; /* binary driver, and tegra constant */
883 u32 max_ac_packet;
884
885 nv_connector = nouveau_encoder_connector_get(nv_encoder);
886 if (!drm_detect_hdmi_monitor(nv_connector->edid))
887 return;
888
889 max_ac_packet = mode->htotal - mode->hdisplay;
890 max_ac_packet -= rekey;
891 max_ac_packet -= 18; /* constant from tegra */
892 max_ac_packet /= 32;
893
894 /* AVI InfoFrame */
895 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000000);
896 nv_wr32(dev, 0x61671c + head, 0x000d0282);
897 nv_wr32(dev, 0x616720 + head, 0x0000006f);
898 nv_wr32(dev, 0x616724 + head, 0x00000000);
899 nv_wr32(dev, 0x616728 + head, 0x00000000);
900 nv_wr32(dev, 0x61672c + head, 0x00000000);
901 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000001);
902
903 /* ??? InfoFrame? */
904 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000000);
905 nv_wr32(dev, 0x6167ac + head, 0x00000010);
906 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000001);
907
908 /* HDMI_CTRL */
909 nv_mask(dev, 0x616798 + head, 0x401f007f, 0x40000000 | rekey |
910 max_ac_packet << 16);
911
Ben Skeggs091e40c2011-11-11 20:46:00 +1000912 /* NFI, audio doesn't work without it though.. */
913 nv_mask(dev, 0x616548 + head, 0x00000070, 0x00000000);
914
Ben Skeggs78951d22011-11-11 18:13:13 +1000915 nvd0_audio_mode_set(encoder, mode);
916}
917
918static void
919nvd0_hdmi_disconnect(struct drm_encoder *encoder)
920{
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000921 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
922 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
923 struct drm_device *dev = encoder->dev;
924 int head = nv_crtc->index * 0x800;
925
Ben Skeggs78951d22011-11-11 18:13:13 +1000926 nvd0_audio_disconnect(encoder);
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000927
928 nv_mask(dev, 0x616798 + head, 0x40000000, 0x00000000);
929 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000000);
930 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000000);
Ben Skeggs78951d22011-11-11 18:13:13 +1000931}
932
933/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +1000934 * SOR
935 *****************************************************************************/
Ben Skeggs83fc0832011-07-05 13:08:40 +1000936static void
937nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
938{
939 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
940 struct drm_device *dev = encoder->dev;
941 struct drm_encoder *partner;
942 int or = nv_encoder->or;
943 u32 dpms_ctrl;
944
945 nv_encoder->last_dpms = mode;
946
947 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
948 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
949
950 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
951 continue;
952
953 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +1000954 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +1000955 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
956 return;
957 break;
958 }
959 }
960
961 dpms_ctrl = (mode == DRM_MODE_DPMS_ON);
962 dpms_ctrl |= 0x80000000;
963
964 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
965 nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
966 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
967 nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
968}
969
970static bool
971nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
972 struct drm_display_mode *adjusted_mode)
973{
974 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
975 struct nouveau_connector *nv_connector;
976
977 nv_connector = nouveau_encoder_connector_get(nv_encoder);
978 if (nv_connector && nv_connector->native_mode) {
979 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
980 int id = adjusted_mode->base.id;
981 *adjusted_mode = *nv_connector->native_mode;
982 adjusted_mode->base.id = id;
983 }
984 }
985
986 return true;
987}
988
989static void
990nvd0_sor_prepare(struct drm_encoder *encoder)
991{
992}
993
994static void
995nvd0_sor_commit(struct drm_encoder *encoder)
996{
997}
998
999static void
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001000nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
1001 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001002{
Ben Skeggs78951d22011-11-11 18:13:13 +10001003 struct drm_device *dev = encoder->dev;
1004 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001005 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1006 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001007 struct nouveau_connector *nv_connector;
1008 struct nvbios *bios = &dev_priv->vbios;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001009 u32 mode_ctrl = (1 << nv_crtc->index);
Ben Skeggsff8ff502011-07-08 11:53:37 +10001010 u32 *push, or_config;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001011
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001012 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1013 switch (nv_encoder->dcb->type) {
1014 case OUTPUT_TMDS:
1015 if (nv_encoder->dcb->sorconf.link & 1) {
1016 if (mode->clock < 165000)
1017 mode_ctrl |= 0x00000100;
1018 else
1019 mode_ctrl |= 0x00000500;
1020 } else {
1021 mode_ctrl |= 0x00000200;
1022 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10001023
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001024 or_config = (mode_ctrl & 0x00000f00) >> 8;
1025 if (mode->clock >= 165000)
1026 or_config |= 0x0100;
Ben Skeggs78951d22011-11-11 18:13:13 +10001027
1028 nvd0_hdmi_mode_set(encoder, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001029 break;
1030 case OUTPUT_LVDS:
1031 or_config = (mode_ctrl & 0x00000f00) >> 8;
1032 if (bios->fp_no_ddc) {
1033 if (bios->fp.dual_link)
1034 or_config |= 0x0100;
1035 if (bios->fp.if_is_24bit)
1036 or_config |= 0x0200;
1037 } else {
1038 if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
1039 if (((u8 *)nv_connector->edid)[121] == 2)
1040 or_config |= 0x0100;
1041 } else
1042 if (mode->clock >= bios->fp.duallink_transition_clk) {
1043 or_config |= 0x0100;
1044 }
1045
1046 if (or_config & 0x0100) {
1047 if (bios->fp.strapless_is_24bit & 2)
1048 or_config |= 0x0200;
1049 } else {
1050 if (bios->fp.strapless_is_24bit & 1)
1051 or_config |= 0x0200;
1052 }
1053
1054 if (nv_connector->base.display_info.bpc == 8)
1055 or_config |= 0x0200;
1056
1057 }
1058 break;
1059 default:
1060 BUG_ON(1);
1061 break;
1062 }
Ben Skeggsff8ff502011-07-08 11:53:37 +10001063
Ben Skeggs83fc0832011-07-05 13:08:40 +10001064 nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
1065
Ben Skeggs78951d22011-11-11 18:13:13 +10001066 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001067 if (push) {
Ben Skeggsff8ff502011-07-08 11:53:37 +10001068 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001069 evo_data(push, mode_ctrl);
Ben Skeggsff8ff502011-07-08 11:53:37 +10001070 evo_data(push, or_config);
Ben Skeggs78951d22011-11-11 18:13:13 +10001071 evo_kick(push, dev, 0);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001072 }
1073
1074 nv_encoder->crtc = encoder->crtc;
1075}
1076
1077static void
1078nvd0_sor_disconnect(struct drm_encoder *encoder)
1079{
1080 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1081 struct drm_device *dev = encoder->dev;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001082 u32 *push;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001083
1084 if (nv_encoder->crtc) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10001085 nvd0_crtc_prepare(nv_encoder->crtc);
1086
1087 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001088 if (push) {
1089 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
1090 evo_data(push, 0x00000000);
1091 evo_mthd(push, 0x0080, 1);
1092 evo_data(push, 0x00000000);
1093 evo_kick(push, dev, 0);
1094 }
1095
Ben Skeggs78951d22011-11-11 18:13:13 +10001096 nvd0_hdmi_disconnect(encoder);
1097
Ben Skeggs83fc0832011-07-05 13:08:40 +10001098 nv_encoder->crtc = NULL;
1099 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1100 }
1101}
1102
1103static void
1104nvd0_sor_destroy(struct drm_encoder *encoder)
1105{
1106 drm_encoder_cleanup(encoder);
1107 kfree(encoder);
1108}
1109
1110static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = {
1111 .dpms = nvd0_sor_dpms,
1112 .mode_fixup = nvd0_sor_mode_fixup,
1113 .prepare = nvd0_sor_prepare,
1114 .commit = nvd0_sor_commit,
1115 .mode_set = nvd0_sor_mode_set,
1116 .disable = nvd0_sor_disconnect,
1117 .get_crtc = nvd0_display_crtc_get,
1118};
1119
1120static const struct drm_encoder_funcs nvd0_sor_func = {
1121 .destroy = nvd0_sor_destroy,
1122};
1123
1124static int
1125nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe)
1126{
1127 struct drm_device *dev = connector->dev;
1128 struct nouveau_encoder *nv_encoder;
1129 struct drm_encoder *encoder;
1130
1131 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
1132 if (!nv_encoder)
1133 return -ENOMEM;
1134 nv_encoder->dcb = dcbe;
1135 nv_encoder->or = ffs(dcbe->or) - 1;
1136 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1137
1138 encoder = to_drm_encoder(nv_encoder);
1139 encoder->possible_crtcs = dcbe->heads;
1140 encoder->possible_clones = 0;
1141 drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS);
1142 drm_encoder_helper_add(encoder, &nvd0_sor_hfunc);
1143
1144 drm_mode_connector_attach_encoder(connector, encoder);
1145 return 0;
1146}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001147
1148/******************************************************************************
1149 * IRQ
1150 *****************************************************************************/
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001151static struct dcb_entry *
1152lookup_dcb(struct drm_device *dev, int id, u32 mc)
1153{
1154 struct drm_nouveau_private *dev_priv = dev->dev_private;
1155 int type, or, i;
1156
1157 if (id < 4) {
1158 type = OUTPUT_ANALOG;
1159 or = id;
1160 } else {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001161 switch (mc & 0x00000f00) {
1162 case 0x00000000: type = OUTPUT_LVDS; break;
1163 case 0x00000100: type = OUTPUT_TMDS; break;
1164 case 0x00000200: type = OUTPUT_TMDS; break;
1165 case 0x00000500: type = OUTPUT_TMDS; break;
1166 default:
Ben Skeggsee417792011-07-08 14:34:45 +10001167 NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001168 return NULL;
1169 }
1170
1171 or = id - 4;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001172 }
1173
1174 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
1175 struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
1176 if (dcb->type == type && (dcb->or & (1 << or)))
1177 return dcb;
1178 }
1179
Ben Skeggsee417792011-07-08 14:34:45 +10001180 NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001181 return NULL;
1182}
1183
Ben Skeggs46005222011-07-05 11:01:13 +10001184static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001185nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001186{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001187 struct dcb_entry *dcb;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001188 int i;
1189
Ben Skeggsee417792011-07-08 14:34:45 +10001190 for (i = 0; mask && i < 8; i++) {
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001191 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
Ben Skeggsee417792011-07-08 14:34:45 +10001192 if (!(mcc & (1 << crtc)))
1193 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001194
Ben Skeggsee417792011-07-08 14:34:45 +10001195 dcb = lookup_dcb(dev, i, mcc);
1196 if (!dcb)
1197 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001198
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001199 nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001200 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001201
Ben Skeggs270a5742011-07-05 14:16:05 +10001202 nv_wr32(dev, 0x6101d4, 0x00000000);
1203 nv_wr32(dev, 0x6109d4, 0x00000000);
1204 nv_wr32(dev, 0x6101d0, 0x80000000);
1205}
1206
1207static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001208nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001209{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001210 struct dcb_entry *dcb;
Ben Skeggs37b034a2011-07-08 14:43:19 +10001211 u32 or, tmp, pclk;
Ben Skeggsee417792011-07-08 14:34:45 +10001212 int i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001213
Ben Skeggsee417792011-07-08 14:34:45 +10001214 for (i = 0; mask && i < 8; i++) {
1215 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
1216 if (!(mcc & (1 << crtc)))
1217 continue;
1218
1219 dcb = lookup_dcb(dev, i, mcc);
1220 if (!dcb)
1221 continue;
1222
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001223 nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001224 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001225
Ben Skeggsee417792011-07-08 14:34:45 +10001226 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
1227 if (mask & 0x00010000) {
1228 nv50_crtc_set_clock(dev, crtc, pclk);
1229 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001230
Ben Skeggsee417792011-07-08 14:34:45 +10001231 for (i = 0; mask && i < 8; i++) {
1232 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1233 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1234 if (!(mcp & (1 << crtc)))
1235 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001236
Ben Skeggsee417792011-07-08 14:34:45 +10001237 dcb = lookup_dcb(dev, i, mcp);
1238 if (!dcb)
1239 continue;
1240 or = ffs(dcb->or) - 1;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001241
Ben Skeggsee417792011-07-08 14:34:45 +10001242 nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001243
Ben Skeggsee417792011-07-08 14:34:45 +10001244 nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000);
1245 switch (dcb->type) {
1246 case OUTPUT_ANALOG:
1247 nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000);
1248 break;
1249 case OUTPUT_TMDS:
1250 case OUTPUT_LVDS:
1251 if (cfg & 0x00000100)
1252 tmp = 0x00000101;
1253 else
1254 tmp = 0x00000000;
1255
1256 nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
1257 break;
1258 default:
1259 break;
1260 }
1261
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001262 break;
1263 }
1264
Ben Skeggs270a5742011-07-05 14:16:05 +10001265 nv_wr32(dev, 0x6101d4, 0x00000000);
1266 nv_wr32(dev, 0x6109d4, 0x00000000);
1267 nv_wr32(dev, 0x6101d0, 0x80000000);
1268}
1269
1270static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001271nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001272{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001273 struct dcb_entry *dcb;
Ben Skeggsee417792011-07-08 14:34:45 +10001274 int pclk, i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001275
Ben Skeggsee417792011-07-08 14:34:45 +10001276 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001277
Ben Skeggsee417792011-07-08 14:34:45 +10001278 for (i = 0; mask && i < 8; i++) {
1279 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1280 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1281 if (!(mcp & (1 << crtc)))
1282 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001283
Ben Skeggsee417792011-07-08 14:34:45 +10001284 dcb = lookup_dcb(dev, i, mcp);
1285 if (!dcb)
1286 continue;
1287
1288 nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc);
1289 }
1290
Ben Skeggs270a5742011-07-05 14:16:05 +10001291 nv_wr32(dev, 0x6101d4, 0x00000000);
1292 nv_wr32(dev, 0x6109d4, 0x00000000);
1293 nv_wr32(dev, 0x6101d0, 0x80000000);
1294}
1295
1296static void
Ben Skeggsf20ce962011-07-08 13:17:01 +10001297nvd0_display_bh(unsigned long data)
1298{
1299 struct drm_device *dev = (struct drm_device *)data;
1300 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001301 u32 mask, crtc;
1302 int i;
1303
1304 if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
1305 NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset);
1306 NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n",
1307 nv_rd32(dev, 0x6101d0),
1308 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
1309 for (i = 0; i < 8; i++) {
1310 NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n",
1311 i < 4 ? "DAC" : "SOR", i,
1312 nv_rd32(dev, 0x640180 + (i * 0x20)),
1313 nv_rd32(dev, 0x660180 + (i * 0x20)));
1314 }
1315 }
1316
1317 mask = nv_rd32(dev, 0x6101d4);
1318 crtc = 0;
1319 if (!mask) {
1320 mask = nv_rd32(dev, 0x6109d4);
1321 crtc = 1;
1322 }
Ben Skeggsf20ce962011-07-08 13:17:01 +10001323
Ben Skeggsee417792011-07-08 14:34:45 +10001324 if (disp->modeset & 0x00000001)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001325 nvd0_display_unk1_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001326 if (disp->modeset & 0x00000002)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001327 nvd0_display_unk2_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001328 if (disp->modeset & 0x00000004)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001329 nvd0_display_unk4_handler(dev, crtc, mask);
Ben Skeggsf20ce962011-07-08 13:17:01 +10001330}
1331
1332static void
Ben Skeggs46005222011-07-05 11:01:13 +10001333nvd0_display_intr(struct drm_device *dev)
1334{
Ben Skeggsf20ce962011-07-08 13:17:01 +10001335 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001336 u32 intr = nv_rd32(dev, 0x610088);
1337
1338 if (intr & 0x00000002) {
1339 u32 stat = nv_rd32(dev, 0x61009c);
1340 int chid = ffs(stat) - 1;
1341 if (chid >= 0) {
1342 u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12));
1343 u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12));
1344 u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12));
1345
1346 NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x "
1347 "0x%08x 0x%08x\n",
1348 chid, (mthd & 0x0000ffc), data, mthd, unkn);
1349 nv_wr32(dev, 0x61009c, (1 << chid));
1350 nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000);
1351 }
1352
1353 intr &= ~0x00000002;
1354 }
1355
Ben Skeggs270a5742011-07-05 14:16:05 +10001356 if (intr & 0x00100000) {
1357 u32 stat = nv_rd32(dev, 0x6100ac);
1358
1359 if (stat & 0x00000007) {
Ben Skeggsee417792011-07-08 14:34:45 +10001360 disp->modeset = stat;
Ben Skeggsf20ce962011-07-08 13:17:01 +10001361 tasklet_schedule(&disp->tasklet);
Ben Skeggs270a5742011-07-05 14:16:05 +10001362
Ben Skeggsf20ce962011-07-08 13:17:01 +10001363 nv_wr32(dev, 0x6100ac, (stat & 0x00000007));
Ben Skeggs270a5742011-07-05 14:16:05 +10001364 stat &= ~0x00000007;
1365 }
1366
1367 if (stat) {
1368 NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat);
1369 nv_wr32(dev, 0x6100ac, stat);
1370 }
1371
1372 intr &= ~0x00100000;
1373 }
1374
Ben Skeggs46005222011-07-05 11:01:13 +10001375 if (intr & 0x01000000) {
1376 u32 stat = nv_rd32(dev, 0x6100bc);
1377 nv_wr32(dev, 0x6100bc, stat);
1378 intr &= ~0x01000000;
1379 }
1380
1381 if (intr & 0x02000000) {
1382 u32 stat = nv_rd32(dev, 0x6108bc);
1383 nv_wr32(dev, 0x6108bc, stat);
1384 intr &= ~0x02000000;
1385 }
1386
1387 if (intr)
1388 NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr);
1389}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001390
1391/******************************************************************************
1392 * Init
1393 *****************************************************************************/
Ben Skeggs2a44e492011-11-09 11:36:33 +10001394void
Ben Skeggs26f6d882011-07-04 16:25:18 +10001395nvd0_display_fini(struct drm_device *dev)
1396{
1397 int i;
1398
1399 /* fini cursors */
1400 for (i = 14; i >= 13; i--) {
1401 if (!(nv_rd32(dev, 0x610490 + (i * 0x10)) & 0x00000001))
1402 continue;
1403
1404 nv_mask(dev, 0x610490 + (i * 0x10), 0x00000001, 0x00000000);
1405 nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00000000);
1406 nv_mask(dev, 0x610090, 1 << i, 0x00000000);
1407 nv_mask(dev, 0x6100a0, 1 << i, 0x00000000);
1408 }
1409
1410 /* fini master */
1411 if (nv_rd32(dev, 0x610490) & 0x00000010) {
1412 nv_mask(dev, 0x610490, 0x00000010, 0x00000000);
1413 nv_mask(dev, 0x610490, 0x00000003, 0x00000000);
1414 nv_wait(dev, 0x610490, 0x80000000, 0x00000000);
1415 nv_mask(dev, 0x610090, 0x00000001, 0x00000000);
1416 nv_mask(dev, 0x6100a0, 0x00000001, 0x00000000);
1417 }
1418}
1419
1420int
1421nvd0_display_init(struct drm_device *dev)
1422{
1423 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001424 u32 *push;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001425 int i;
1426
1427 if (nv_rd32(dev, 0x6100ac) & 0x00000100) {
1428 nv_wr32(dev, 0x6100ac, 0x00000100);
1429 nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000);
1430 if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) {
1431 NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n",
1432 nv_rd32(dev, 0x6194e8));
1433 return -EBUSY;
1434 }
1435 }
1436
Ben Skeggsa36f04c2011-07-06 14:39:23 +10001437 /* nfi what these are exactly, i do know that SOR_MODE_CTRL won't
1438 * work at all unless you do the SOR part below.
1439 */
1440 for (i = 0; i < 3; i++) {
1441 u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800));
1442 nv_wr32(dev, 0x6101c0 + (i * 0x800), dac);
1443 }
1444
1445 for (i = 0; i < 4; i++) {
1446 u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800));
1447 nv_wr32(dev, 0x6301c4 + (i * 0x800), sor);
1448 }
1449
1450 for (i = 0; i < 2; i++) {
1451 u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800));
1452 u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800));
1453 u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800));
1454 nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0);
1455 nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1);
1456 nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2);
1457 }
1458
1459 /* point at our hash table / objects, enable interrupts */
Ben Skeggs26f6d882011-07-04 16:25:18 +10001460 nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9);
Ben Skeggs270a5742011-07-05 14:16:05 +10001461 nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001462
1463 /* init master */
Ben Skeggs51beb422011-07-05 10:33:08 +10001464 nv_wr32(dev, 0x610494, (disp->evo[0].handle >> 8) | 3);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001465 nv_wr32(dev, 0x610498, 0x00010000);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001466 nv_wr32(dev, 0x61049c, 0x00000001);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001467 nv_mask(dev, 0x610490, 0x00000010, 0x00000010);
1468 nv_wr32(dev, 0x640000, 0x00000000);
1469 nv_wr32(dev, 0x610490, 0x01000013);
1470 if (!nv_wait(dev, 0x610490, 0x80000000, 0x00000000)) {
1471 NV_ERROR(dev, "PDISP: master 0x%08x\n",
1472 nv_rd32(dev, 0x610490));
1473 return -EBUSY;
1474 }
1475 nv_mask(dev, 0x610090, 0x00000001, 0x00000001);
1476 nv_mask(dev, 0x6100a0, 0x00000001, 0x00000001);
1477
1478 /* init cursors */
1479 for (i = 13; i <= 14; i++) {
1480 nv_wr32(dev, 0x610490 + (i * 0x10), 0x00000001);
1481 if (!nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00010000)) {
1482 NV_ERROR(dev, "PDISP: curs%d 0x%08x\n", i,
1483 nv_rd32(dev, 0x610490 + (i * 0x10)));
1484 return -EBUSY;
1485 }
1486
1487 nv_mask(dev, 0x610090, 1 << i, 1 << i);
1488 nv_mask(dev, 0x6100a0, 1 << i, 1 << i);
1489 }
1490
Ben Skeggsefd272a2011-07-05 11:58:58 +10001491 push = evo_wait(dev, 0, 32);
1492 if (!push)
1493 return -EBUSY;
1494 evo_mthd(push, 0x0088, 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001495 evo_data(push, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001496 evo_mthd(push, 0x0084, 1);
1497 evo_data(push, 0x00000000);
1498 evo_mthd(push, 0x0084, 1);
1499 evo_data(push, 0x80000000);
1500 evo_mthd(push, 0x008c, 1);
1501 evo_data(push, 0x00000000);
1502 evo_kick(push, dev, 0);
1503
Ben Skeggs26f6d882011-07-04 16:25:18 +10001504 return 0;
1505}
1506
1507void
1508nvd0_display_destroy(struct drm_device *dev)
1509{
1510 struct drm_nouveau_private *dev_priv = dev->dev_private;
1511 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs51beb422011-07-05 10:33:08 +10001512 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001513
Ben Skeggs51beb422011-07-05 10:33:08 +10001514 pci_free_consistent(pdev, PAGE_SIZE, disp->evo[0].ptr, disp->evo[0].handle);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001515 nouveau_gpuobj_ref(NULL, &disp->mem);
Ben Skeggs46005222011-07-05 11:01:13 +10001516 nouveau_irq_unregister(dev, 26);
Ben Skeggs51beb422011-07-05 10:33:08 +10001517
1518 dev_priv->engine.display.priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001519 kfree(disp);
1520}
1521
1522int
1523nvd0_display_create(struct drm_device *dev)
1524{
1525 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsefd272a2011-07-05 11:58:58 +10001526 struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001527 struct dcb_table *dcb = &dev_priv->vbios.dcb;
1528 struct drm_connector *connector, *tmp;
Ben Skeggs51beb422011-07-05 10:33:08 +10001529 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001530 struct nvd0_display *disp;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001531 struct dcb_entry *dcbe;
1532 int ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001533
1534 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
1535 if (!disp)
1536 return -ENOMEM;
1537 dev_priv->engine.display.priv = disp;
1538
Ben Skeggs438d99e2011-07-05 16:48:06 +10001539 /* create crtc objects to represent the hw heads */
1540 for (i = 0; i < 2; i++) {
1541 ret = nvd0_crtc_create(dev, i);
1542 if (ret)
1543 goto out;
1544 }
1545
Ben Skeggs83fc0832011-07-05 13:08:40 +10001546 /* create encoder/connector objects based on VBIOS DCB table */
1547 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
1548 connector = nouveau_connector_create(dev, dcbe->connector);
1549 if (IS_ERR(connector))
1550 continue;
1551
1552 if (dcbe->location != DCB_LOC_ON_CHIP) {
1553 NV_WARN(dev, "skipping off-chip encoder %d/%d\n",
1554 dcbe->type, ffs(dcbe->or) - 1);
1555 continue;
1556 }
1557
1558 switch (dcbe->type) {
1559 case OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001560 case OUTPUT_LVDS:
Ben Skeggs83fc0832011-07-05 13:08:40 +10001561 nvd0_sor_create(connector, dcbe);
1562 break;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001563 case OUTPUT_ANALOG:
1564 nvd0_dac_create(connector, dcbe);
1565 break;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001566 default:
1567 NV_WARN(dev, "skipping unsupported encoder %d/%d\n",
1568 dcbe->type, ffs(dcbe->or) - 1);
1569 continue;
1570 }
1571 }
1572
1573 /* cull any connectors we created that don't have an encoder */
1574 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
1575 if (connector->encoder_ids[0])
1576 continue;
1577
1578 NV_WARN(dev, "%s has no encoders, removing\n",
1579 drm_get_connector_name(connector));
1580 connector->funcs->destroy(connector);
1581 }
1582
Ben Skeggs46005222011-07-05 11:01:13 +10001583 /* setup interrupt handling */
Ben Skeggsf20ce962011-07-08 13:17:01 +10001584 tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001585 nouveau_irq_register(dev, 26, nvd0_display_intr);
1586
Ben Skeggs51beb422011-07-05 10:33:08 +10001587 /* hash table and dma objects for the memory areas we care about */
Ben Skeggsefd272a2011-07-05 11:58:58 +10001588 ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000,
1589 NVOBJ_FLAG_ZERO_ALLOC, &disp->mem);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001590 if (ret)
1591 goto out;
1592
Ben Skeggsefd272a2011-07-05 11:58:58 +10001593 nv_wo32(disp->mem, 0x1000, 0x00000049);
1594 nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8);
1595 nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8);
1596 nv_wo32(disp->mem, 0x100c, 0x00000000);
1597 nv_wo32(disp->mem, 0x1010, 0x00000000);
1598 nv_wo32(disp->mem, 0x1014, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001599 nv_wo32(disp->mem, 0x0000, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001600 nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001);
1601
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001602 nv_wo32(disp->mem, 0x1020, 0x00000049);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001603 nv_wo32(disp->mem, 0x1024, 0x00000000);
1604 nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8);
1605 nv_wo32(disp->mem, 0x102c, 0x00000000);
1606 nv_wo32(disp->mem, 0x1030, 0x00000000);
1607 nv_wo32(disp->mem, 0x1034, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001608 nv_wo32(disp->mem, 0x0008, NvEvoVRAM);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001609 nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001);
1610
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001611 nv_wo32(disp->mem, 0x1040, 0x00000009);
1612 nv_wo32(disp->mem, 0x1044, 0x00000000);
1613 nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8);
1614 nv_wo32(disp->mem, 0x104c, 0x00000000);
1615 nv_wo32(disp->mem, 0x1050, 0x00000000);
1616 nv_wo32(disp->mem, 0x1054, 0x00000000);
1617 nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP);
1618 nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001);
1619
1620 nv_wo32(disp->mem, 0x1060, 0x0fe00009);
1621 nv_wo32(disp->mem, 0x1064, 0x00000000);
1622 nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8);
1623 nv_wo32(disp->mem, 0x106c, 0x00000000);
1624 nv_wo32(disp->mem, 0x1070, 0x00000000);
1625 nv_wo32(disp->mem, 0x1074, 0x00000000);
1626 nv_wo32(disp->mem, 0x0018, NvEvoFB32);
1627 nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001);
1628
Ben Skeggsefd272a2011-07-05 11:58:58 +10001629 pinstmem->flush(dev);
1630
Ben Skeggs51beb422011-07-05 10:33:08 +10001631 /* push buffers for evo channels */
1632 disp->evo[0].ptr =
1633 pci_alloc_consistent(pdev, PAGE_SIZE, &disp->evo[0].handle);
1634 if (!disp->evo[0].ptr) {
1635 ret = -ENOMEM;
1636 goto out;
1637 }
1638
Ben Skeggs26f6d882011-07-04 16:25:18 +10001639out:
1640 if (ret)
1641 nvd0_display_destroy(dev);
1642 return ret;
1643}