blob: 614c6520a52008b80490c1757be6d1fe98baddbc [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{
163 struct drm_display_mode *mode = &nv_crtc->base.mode;
164 struct drm_device *dev = nv_crtc->base.dev;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000165 struct nouveau_connector *nv_connector;
166 u32 *push, outX, outY;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000167
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000168 outX = mode->hdisplay;
169 outY = mode->vdisplay;
170
171 nv_connector = nouveau_crtc_connector_get(nv_crtc);
172 if (nv_connector && nv_connector->native_mode) {
173 struct drm_display_mode *native = nv_connector->native_mode;
174 u32 xratio = (native->hdisplay << 19) / mode->hdisplay;
175 u32 yratio = (native->vdisplay << 19) / mode->vdisplay;
176
Ben Skeggs488ff202011-10-17 10:38:10 +1000177 switch (nv_connector->scaling_mode) {
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000178 case DRM_MODE_SCALE_ASPECT:
179 if (xratio > yratio) {
180 outX = (mode->hdisplay * yratio) >> 19;
181 outY = (mode->vdisplay * yratio) >> 19;
182 } else {
183 outX = (mode->hdisplay * xratio) >> 19;
184 outY = (mode->vdisplay * xratio) >> 19;
185 }
186 break;
187 case DRM_MODE_SCALE_FULLSCREEN:
188 outX = native->hdisplay;
189 outY = native->vdisplay;
190 break;
191 default:
192 break;
193 }
194 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000195
196 push = evo_wait(dev, 0, 16);
197 if (push) {
198 evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000199 evo_data(push, (outY << 16) | outX);
200 evo_data(push, (outY << 16) | outX);
201 evo_data(push, (outY << 16) | outX);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000202 evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
203 evo_data(push, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000204 evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
205 evo_data(push, (mode->vdisplay << 16) | mode->hdisplay);
206 if (update) {
207 evo_mthd(push, 0x0080, 1);
208 evo_data(push, 0x00000000);
209 }
210 evo_kick(push, dev, 0);
211 }
212
213 return 0;
214}
215
216static int
217nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
218 int x, int y, bool update)
219{
220 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
221 u32 *push;
222
Ben Skeggs438d99e2011-07-05 16:48:06 +1000223 push = evo_wait(fb->dev, 0, 16);
224 if (push) {
225 evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1);
226 evo_data(push, nvfb->nvbo->bo.offset >> 8);
227 evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4);
228 evo_data(push, (fb->height << 16) | fb->width);
229 evo_data(push, nvfb->r_pitch);
230 evo_data(push, nvfb->r_format);
Ben Skeggsc0cc92a2011-07-06 11:40:45 +1000231 evo_data(push, nvfb->r_dma);
Ben Skeggsc6f2f712011-07-08 12:11:58 +1000232 evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1);
233 evo_data(push, (y << 16) | x);
Ben Skeggsa46232e2011-07-07 15:23:48 +1000234 if (update) {
235 evo_mthd(push, 0x0080, 1);
236 evo_data(push, 0x00000000);
237 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000238 evo_kick(push, fb->dev, 0);
239 }
240
Ben Skeggsc0cc92a2011-07-06 11:40:45 +1000241 nv_crtc->fb.tile_flags = nvfb->r_dma;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000242 return 0;
243}
244
245static void
246nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update)
247{
248 struct drm_device *dev = nv_crtc->base.dev;
249 u32 *push = evo_wait(dev, 0, 16);
250 if (push) {
251 if (show) {
252 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
253 evo_data(push, 0x85000000);
254 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
255 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +1000256 evo_data(push, NvEvoVRAM);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000257 } else {
258 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1);
259 evo_data(push, 0x05000000);
260 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
261 evo_data(push, 0x00000000);
262 }
263
264 if (update) {
265 evo_mthd(push, 0x0080, 1);
266 evo_data(push, 0x00000000);
267 }
268
269 evo_kick(push, dev, 0);
270 }
271}
272
273static void
274nvd0_crtc_dpms(struct drm_crtc *crtc, int mode)
275{
276}
277
278static void
279nvd0_crtc_prepare(struct drm_crtc *crtc)
280{
281 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
282 u32 *push;
283
284 push = evo_wait(crtc->dev, 0, 2);
285 if (push) {
286 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
287 evo_data(push, 0x00000000);
288 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1);
289 evo_data(push, 0x03000000);
290 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
291 evo_data(push, 0x00000000);
292 evo_kick(push, crtc->dev, 0);
293 }
294
295 nvd0_crtc_cursor_show(nv_crtc, false, false);
296}
297
298static void
299nvd0_crtc_commit(struct drm_crtc *crtc)
300{
301 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
302 u32 *push;
303
304 push = evo_wait(crtc->dev, 0, 32);
305 if (push) {
306 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
307 evo_data(push, nv_crtc->fb.tile_flags);
308 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4);
309 evo_data(push, 0x83000000);
310 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
311 evo_data(push, 0x00000000);
312 evo_data(push, 0x00000000);
313 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +1000314 evo_data(push, NvEvoVRAM);
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000315 evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1);
316 evo_data(push, 0xffffff00);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000317 evo_kick(push, crtc->dev, 0);
318 }
319
320 nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true);
321}
322
323static bool
324nvd0_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
325 struct drm_display_mode *adjusted_mode)
326{
327 return true;
328}
329
330static int
331nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
332{
333 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
334 int ret;
335
336 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
337 if (ret)
338 return ret;
339
340 if (old_fb) {
341 nvfb = nouveau_framebuffer(old_fb);
342 nouveau_bo_unpin(nvfb->nvbo);
343 }
344
345 return 0;
346}
347
348static int
349nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
350 struct drm_display_mode *mode, int x, int y,
351 struct drm_framebuffer *old_fb)
352{
353 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
354 struct nouveau_connector *nv_connector;
355 u32 htotal = mode->htotal;
356 u32 vtotal = mode->vtotal;
357 u32 hsyncw = mode->hsync_end - mode->hsync_start - 1;
358 u32 vsyncw = mode->vsync_end - mode->vsync_start - 1;
359 u32 hfrntp = mode->hsync_start - mode->hdisplay;
360 u32 vfrntp = mode->vsync_start - mode->vdisplay;
361 u32 hbackp = mode->htotal - mode->hsync_end;
362 u32 vbackp = mode->vtotal - mode->vsync_end;
363 u32 hss2be = hsyncw + hbackp;
364 u32 vss2be = vsyncw + vbackp;
365 u32 hss2de = htotal - hfrntp;
366 u32 vss2de = vtotal - vfrntp;
Ben Skeggs629c1b92011-07-08 09:43:20 +1000367 u32 syncs, *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000368 int ret;
369
Ben Skeggs629c1b92011-07-08 09:43:20 +1000370 syncs = 0x00000001;
371 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
372 syncs |= 0x00000008;
373 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
374 syncs |= 0x00000010;
375
Ben Skeggs438d99e2011-07-05 16:48:06 +1000376 ret = nvd0_crtc_swap_fbs(crtc, old_fb);
377 if (ret)
378 return ret;
379
380 push = evo_wait(crtc->dev, 0, 64);
381 if (push) {
382 evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 5);
Ben Skeggs629c1b92011-07-08 09:43:20 +1000383 evo_data(push, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000384 evo_data(push, (vtotal << 16) | htotal);
385 evo_data(push, (vsyncw << 16) | hsyncw);
386 evo_data(push, (vss2be << 16) | hss2be);
387 evo_data(push, (vss2de << 16) | hss2de);
388 evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1);
389 evo_data(push, 0x00000000); /* ??? */
390 evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3);
391 evo_data(push, mode->clock * 1000);
392 evo_data(push, 0x00200000); /* ??? */
393 evo_data(push, mode->clock * 1000);
Ben Skeggs629c1b92011-07-08 09:43:20 +1000394 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 1);
395 evo_data(push, syncs);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000396 evo_kick(push, crtc->dev, 0);
397 }
398
399 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggs488ff202011-10-17 10:38:10 +1000400 nvd0_crtc_set_dither(nv_crtc, false);
401 nvd0_crtc_set_scale(nv_crtc, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000402 nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
403 return 0;
404}
405
406static int
407nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
408 struct drm_framebuffer *old_fb)
409{
410 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
411 int ret;
412
Ben Skeggs84e2ad82011-08-26 09:40:39 +1000413 if (!crtc->fb) {
414 NV_DEBUG_KMS(crtc->dev, "No FB bound\n");
415 return 0;
416 }
417
Ben Skeggs438d99e2011-07-05 16:48:06 +1000418 ret = nvd0_crtc_swap_fbs(crtc, old_fb);
419 if (ret)
420 return ret;
421
422 nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
423 return 0;
424}
425
426static int
427nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
428 struct drm_framebuffer *fb, int x, int y,
429 enum mode_set_atomic state)
430{
431 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
432 nvd0_crtc_set_image(nv_crtc, fb, x, y, true);
433 return 0;
434}
435
436static void
437nvd0_crtc_lut_load(struct drm_crtc *crtc)
438{
439 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
440 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
441 int i;
442
443 for (i = 0; i < 256; i++) {
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000444 writew(0x6000 + (nv_crtc->lut.r[i] >> 2), lut + (i * 0x20) + 0);
445 writew(0x6000 + (nv_crtc->lut.g[i] >> 2), lut + (i * 0x20) + 2);
446 writew(0x6000 + (nv_crtc->lut.b[i] >> 2), lut + (i * 0x20) + 4);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000447 }
448}
449
450static int
451nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
452 uint32_t handle, uint32_t width, uint32_t height)
453{
454 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
455 struct drm_device *dev = crtc->dev;
456 struct drm_gem_object *gem;
457 struct nouveau_bo *nvbo;
458 bool visible = (handle != 0);
459 int i, ret = 0;
460
461 if (visible) {
462 if (width != 64 || height != 64)
463 return -EINVAL;
464
465 gem = drm_gem_object_lookup(dev, file_priv, handle);
466 if (unlikely(!gem))
467 return -ENOENT;
468 nvbo = nouveau_gem_object(gem);
469
470 ret = nouveau_bo_map(nvbo);
471 if (ret == 0) {
472 for (i = 0; i < 64 * 64; i++) {
473 u32 v = nouveau_bo_rd32(nvbo, i);
474 nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v);
475 }
476 nouveau_bo_unmap(nvbo);
477 }
478
479 drm_gem_object_unreference_unlocked(gem);
480 }
481
482 if (visible != nv_crtc->cursor.visible) {
483 nvd0_crtc_cursor_show(nv_crtc, visible, true);
484 nv_crtc->cursor.visible = visible;
485 }
486
487 return ret;
488}
489
490static int
491nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
492{
493 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
494 const u32 data = (y << 16) | x;
495
496 nv_wr32(crtc->dev, 0x64d084 + (nv_crtc->index * 0x1000), data);
497 nv_wr32(crtc->dev, 0x64d080 + (nv_crtc->index * 0x1000), 0x00000000);
498 return 0;
499}
500
501static void
502nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
503 uint32_t start, uint32_t size)
504{
505 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
506 u32 end = max(start + size, (u32)256);
507 u32 i;
508
509 for (i = start; i < end; i++) {
510 nv_crtc->lut.r[i] = r[i];
511 nv_crtc->lut.g[i] = g[i];
512 nv_crtc->lut.b[i] = b[i];
513 }
514
515 nvd0_crtc_lut_load(crtc);
516}
517
518static void
519nvd0_crtc_destroy(struct drm_crtc *crtc)
520{
521 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
522 nouveau_bo_unmap(nv_crtc->cursor.nvbo);
523 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
524 nouveau_bo_unmap(nv_crtc->lut.nvbo);
525 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
526 drm_crtc_cleanup(crtc);
527 kfree(crtc);
528}
529
530static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = {
531 .dpms = nvd0_crtc_dpms,
532 .prepare = nvd0_crtc_prepare,
533 .commit = nvd0_crtc_commit,
534 .mode_fixup = nvd0_crtc_mode_fixup,
535 .mode_set = nvd0_crtc_mode_set,
536 .mode_set_base = nvd0_crtc_mode_set_base,
537 .mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic,
538 .load_lut = nvd0_crtc_lut_load,
539};
540
541static const struct drm_crtc_funcs nvd0_crtc_func = {
542 .cursor_set = nvd0_crtc_cursor_set,
543 .cursor_move = nvd0_crtc_cursor_move,
544 .gamma_set = nvd0_crtc_gamma_set,
545 .set_config = drm_crtc_helper_set_config,
546 .destroy = nvd0_crtc_destroy,
547};
548
Ben Skeggsc20ab3e2011-08-25 14:09:43 +1000549static void
550nvd0_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
551{
552}
553
554static void
555nvd0_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
556{
557}
558
Ben Skeggs438d99e2011-07-05 16:48:06 +1000559static int
560nvd0_crtc_create(struct drm_device *dev, int index)
561{
562 struct nouveau_crtc *nv_crtc;
563 struct drm_crtc *crtc;
564 int ret, i;
565
566 nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
567 if (!nv_crtc)
568 return -ENOMEM;
569
570 nv_crtc->index = index;
571 nv_crtc->set_dither = nvd0_crtc_set_dither;
572 nv_crtc->set_scale = nvd0_crtc_set_scale;
Ben Skeggsc20ab3e2011-08-25 14:09:43 +1000573 nv_crtc->cursor.set_offset = nvd0_cursor_set_offset;
574 nv_crtc->cursor.set_pos = nvd0_cursor_set_pos;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000575 for (i = 0; i < 256; i++) {
576 nv_crtc->lut.r[i] = i << 8;
577 nv_crtc->lut.g[i] = i << 8;
578 nv_crtc->lut.b[i] = i << 8;
579 }
580
581 crtc = &nv_crtc->base;
582 drm_crtc_init(dev, crtc, &nvd0_crtc_func);
583 drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc);
584 drm_mode_crtc_set_gamma_size(crtc, 256);
585
586 ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
587 0, 0x0000, &nv_crtc->cursor.nvbo);
588 if (!ret) {
589 ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
590 if (!ret)
591 ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
592 if (ret)
593 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
594 }
595
596 if (ret)
597 goto out;
598
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000599 ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
Ben Skeggs438d99e2011-07-05 16:48:06 +1000600 0, 0x0000, &nv_crtc->lut.nvbo);
601 if (!ret) {
602 ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
603 if (!ret)
604 ret = nouveau_bo_map(nv_crtc->lut.nvbo);
605 if (ret)
606 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
607 }
608
609 if (ret)
610 goto out;
611
612 nvd0_crtc_lut_load(crtc);
613
614out:
615 if (ret)
616 nvd0_crtc_destroy(crtc);
617 return ret;
618}
619
620/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +1000621 * DAC
622 *****************************************************************************/
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000623static void
624nvd0_dac_dpms(struct drm_encoder *encoder, int mode)
625{
626 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
627 struct drm_device *dev = encoder->dev;
628 int or = nv_encoder->or;
629 u32 dpms_ctrl;
630
631 dpms_ctrl = 0x80000000;
632 if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF)
633 dpms_ctrl |= 0x00000001;
634 if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF)
635 dpms_ctrl |= 0x00000004;
636
637 nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
638 nv_mask(dev, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl);
639 nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
640}
641
642static bool
643nvd0_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
644 struct drm_display_mode *adjusted_mode)
645{
646 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
647 struct nouveau_connector *nv_connector;
648
649 nv_connector = nouveau_encoder_connector_get(nv_encoder);
650 if (nv_connector && nv_connector->native_mode) {
651 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
652 int id = adjusted_mode->base.id;
653 *adjusted_mode = *nv_connector->native_mode;
654 adjusted_mode->base.id = id;
655 }
656 }
657
658 return true;
659}
660
661static void
662nvd0_dac_prepare(struct drm_encoder *encoder)
663{
664}
665
666static void
667nvd0_dac_commit(struct drm_encoder *encoder)
668{
669}
670
671static void
672nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
673 struct drm_display_mode *adjusted_mode)
674{
675 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
676 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
677 u32 *push;
678
679 nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON);
680
Ben Skeggsff8ff502011-07-08 11:53:37 +1000681 push = evo_wait(encoder->dev, 0, 4);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000682 if (push) {
Ben Skeggsff8ff502011-07-08 11:53:37 +1000683 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000684 evo_data(push, 1 << nv_crtc->index);
Ben Skeggsff8ff502011-07-08 11:53:37 +1000685 evo_data(push, 0x00ff);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000686 evo_kick(push, encoder->dev, 0);
687 }
688
689 nv_encoder->crtc = encoder->crtc;
690}
691
692static void
693nvd0_dac_disconnect(struct drm_encoder *encoder)
694{
695 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
696 struct drm_device *dev = encoder->dev;
697 u32 *push;
698
699 if (nv_encoder->crtc) {
700 nvd0_crtc_prepare(nv_encoder->crtc);
701
702 push = evo_wait(dev, 0, 4);
703 if (push) {
704 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 1);
705 evo_data(push, 0x00000000);
706 evo_mthd(push, 0x0080, 1);
707 evo_data(push, 0x00000000);
708 evo_kick(push, dev, 0);
709 }
710
711 nv_encoder->crtc = NULL;
712 }
713}
714
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000715static enum drm_connector_status
716nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
717{
Ben Skeggsb6819932011-07-08 11:14:50 +1000718 enum drm_connector_status status = connector_status_disconnected;
719 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
720 struct drm_device *dev = encoder->dev;
721 int or = nv_encoder->or;
722 u32 load;
723
724 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00100000);
725 udelay(9500);
726 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x80000000);
727
728 load = nv_rd32(dev, 0x61a00c + (or * 0x800));
729 if ((load & 0x38000000) == 0x38000000)
730 status = connector_status_connected;
731
732 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00000000);
733 return status;
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000734}
735
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000736static void
737nvd0_dac_destroy(struct drm_encoder *encoder)
738{
739 drm_encoder_cleanup(encoder);
740 kfree(encoder);
741}
742
743static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = {
744 .dpms = nvd0_dac_dpms,
745 .mode_fixup = nvd0_dac_mode_fixup,
746 .prepare = nvd0_dac_prepare,
747 .commit = nvd0_dac_commit,
748 .mode_set = nvd0_dac_mode_set,
749 .disable = nvd0_dac_disconnect,
750 .get_crtc = nvd0_display_crtc_get,
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000751 .detect = nvd0_dac_detect
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000752};
753
754static const struct drm_encoder_funcs nvd0_dac_func = {
755 .destroy = nvd0_dac_destroy,
756};
757
758static int
759nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe)
760{
761 struct drm_device *dev = connector->dev;
762 struct nouveau_encoder *nv_encoder;
763 struct drm_encoder *encoder;
764
765 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
766 if (!nv_encoder)
767 return -ENOMEM;
768 nv_encoder->dcb = dcbe;
769 nv_encoder->or = ffs(dcbe->or) - 1;
770
771 encoder = to_drm_encoder(nv_encoder);
772 encoder->possible_crtcs = dcbe->heads;
773 encoder->possible_clones = 0;
774 drm_encoder_init(dev, encoder, &nvd0_dac_func, DRM_MODE_ENCODER_DAC);
775 drm_encoder_helper_add(encoder, &nvd0_dac_hfunc);
776
777 drm_mode_connector_attach_encoder(connector, encoder);
778 return 0;
779}
Ben Skeggs26f6d882011-07-04 16:25:18 +1000780
781/******************************************************************************
Ben Skeggs78951d22011-11-11 18:13:13 +1000782 * Audio
783 *****************************************************************************/
784static void
785nvd0_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
786{
787 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
788 struct nouveau_connector *nv_connector;
789 struct drm_device *dev = encoder->dev;
790 int i, or = nv_encoder->or * 0x30;
791
792 nv_connector = nouveau_encoder_connector_get(nv_encoder);
793 if (!drm_detect_monitor_audio(nv_connector->edid))
794 return;
795
796 nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000001);
797
798 drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
799 if (nv_connector->base.eld[0]) {
800 u8 *eld = nv_connector->base.eld;
801
802 for (i = 0; i < eld[2] * 4; i++)
803 nv_wr32(dev, 0x10ec00 + or, (i << 8) | eld[i]);
804 for (i = eld[2] * 4; i < 0x60; i++)
805 nv_wr32(dev, 0x10ec00 + or, (i << 8) | 0x00);
806
807 nv_mask(dev, 0x10ec10 + or, 0x80000002, 0x80000002);
808 }
809}
810
811static void
812nvd0_audio_disconnect(struct drm_encoder *encoder)
813{
814 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
815 struct drm_device *dev = encoder->dev;
816 int or = nv_encoder->or * 0x30;
817
818 nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000000);
819}
820
821/******************************************************************************
822 * HDMI
823 *****************************************************************************/
824static void
825nvd0_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
826{
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000827 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
828 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
829 struct nouveau_connector *nv_connector;
830 struct drm_device *dev = encoder->dev;
831 int head = nv_crtc->index * 0x800;
832 u32 rekey = 56; /* binary driver, and tegra constant */
833 u32 max_ac_packet;
834
835 nv_connector = nouveau_encoder_connector_get(nv_encoder);
836 if (!drm_detect_hdmi_monitor(nv_connector->edid))
837 return;
838
839 max_ac_packet = mode->htotal - mode->hdisplay;
840 max_ac_packet -= rekey;
841 max_ac_packet -= 18; /* constant from tegra */
842 max_ac_packet /= 32;
843
844 /* AVI InfoFrame */
845 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000000);
846 nv_wr32(dev, 0x61671c + head, 0x000d0282);
847 nv_wr32(dev, 0x616720 + head, 0x0000006f);
848 nv_wr32(dev, 0x616724 + head, 0x00000000);
849 nv_wr32(dev, 0x616728 + head, 0x00000000);
850 nv_wr32(dev, 0x61672c + head, 0x00000000);
851 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000001);
852
853 /* ??? InfoFrame? */
854 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000000);
855 nv_wr32(dev, 0x6167ac + head, 0x00000010);
856 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000001);
857
858 /* HDMI_CTRL */
859 nv_mask(dev, 0x616798 + head, 0x401f007f, 0x40000000 | rekey |
860 max_ac_packet << 16);
861
Ben Skeggs091e40c2011-11-11 20:46:00 +1000862 /* NFI, audio doesn't work without it though.. */
863 nv_mask(dev, 0x616548 + head, 0x00000070, 0x00000000);
864
Ben Skeggs78951d22011-11-11 18:13:13 +1000865 nvd0_audio_mode_set(encoder, mode);
866}
867
868static void
869nvd0_hdmi_disconnect(struct drm_encoder *encoder)
870{
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000871 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
872 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
873 struct drm_device *dev = encoder->dev;
874 int head = nv_crtc->index * 0x800;
875
Ben Skeggs78951d22011-11-11 18:13:13 +1000876 nvd0_audio_disconnect(encoder);
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000877
878 nv_mask(dev, 0x616798 + head, 0x40000000, 0x00000000);
879 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000000);
880 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000000);
Ben Skeggs78951d22011-11-11 18:13:13 +1000881}
882
883/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +1000884 * SOR
885 *****************************************************************************/
Ben Skeggs83fc0832011-07-05 13:08:40 +1000886static void
887nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
888{
889 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
890 struct drm_device *dev = encoder->dev;
891 struct drm_encoder *partner;
892 int or = nv_encoder->or;
893 u32 dpms_ctrl;
894
895 nv_encoder->last_dpms = mode;
896
897 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
898 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
899
900 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
901 continue;
902
903 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +1000904 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +1000905 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
906 return;
907 break;
908 }
909 }
910
911 dpms_ctrl = (mode == DRM_MODE_DPMS_ON);
912 dpms_ctrl |= 0x80000000;
913
914 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
915 nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
916 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
917 nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
918}
919
920static bool
921nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
922 struct drm_display_mode *adjusted_mode)
923{
924 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
925 struct nouveau_connector *nv_connector;
926
927 nv_connector = nouveau_encoder_connector_get(nv_encoder);
928 if (nv_connector && nv_connector->native_mode) {
929 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
930 int id = adjusted_mode->base.id;
931 *adjusted_mode = *nv_connector->native_mode;
932 adjusted_mode->base.id = id;
933 }
934 }
935
936 return true;
937}
938
939static void
940nvd0_sor_prepare(struct drm_encoder *encoder)
941{
942}
943
944static void
945nvd0_sor_commit(struct drm_encoder *encoder)
946{
947}
948
949static void
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000950nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
951 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +1000952{
Ben Skeggs78951d22011-11-11 18:13:13 +1000953 struct drm_device *dev = encoder->dev;
954 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000955 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
956 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000957 struct nouveau_connector *nv_connector;
958 struct nvbios *bios = &dev_priv->vbios;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000959 u32 mode_ctrl = (1 << nv_crtc->index);
Ben Skeggsff8ff502011-07-08 11:53:37 +1000960 u32 *push, or_config;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000961
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000962 nv_connector = nouveau_encoder_connector_get(nv_encoder);
963 switch (nv_encoder->dcb->type) {
964 case OUTPUT_TMDS:
965 if (nv_encoder->dcb->sorconf.link & 1) {
966 if (mode->clock < 165000)
967 mode_ctrl |= 0x00000100;
968 else
969 mode_ctrl |= 0x00000500;
970 } else {
971 mode_ctrl |= 0x00000200;
972 }
Ben Skeggs83fc0832011-07-05 13:08:40 +1000973
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000974 or_config = (mode_ctrl & 0x00000f00) >> 8;
975 if (mode->clock >= 165000)
976 or_config |= 0x0100;
Ben Skeggs78951d22011-11-11 18:13:13 +1000977
978 nvd0_hdmi_mode_set(encoder, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000979 break;
980 case OUTPUT_LVDS:
981 or_config = (mode_ctrl & 0x00000f00) >> 8;
982 if (bios->fp_no_ddc) {
983 if (bios->fp.dual_link)
984 or_config |= 0x0100;
985 if (bios->fp.if_is_24bit)
986 or_config |= 0x0200;
987 } else {
988 if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
989 if (((u8 *)nv_connector->edid)[121] == 2)
990 or_config |= 0x0100;
991 } else
992 if (mode->clock >= bios->fp.duallink_transition_clk) {
993 or_config |= 0x0100;
994 }
995
996 if (or_config & 0x0100) {
997 if (bios->fp.strapless_is_24bit & 2)
998 or_config |= 0x0200;
999 } else {
1000 if (bios->fp.strapless_is_24bit & 1)
1001 or_config |= 0x0200;
1002 }
1003
1004 if (nv_connector->base.display_info.bpc == 8)
1005 or_config |= 0x0200;
1006
1007 }
1008 break;
1009 default:
1010 BUG_ON(1);
1011 break;
1012 }
Ben Skeggsff8ff502011-07-08 11:53:37 +10001013
Ben Skeggs83fc0832011-07-05 13:08:40 +10001014 nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
1015
Ben Skeggs78951d22011-11-11 18:13:13 +10001016 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001017 if (push) {
Ben Skeggsff8ff502011-07-08 11:53:37 +10001018 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001019 evo_data(push, mode_ctrl);
Ben Skeggsff8ff502011-07-08 11:53:37 +10001020 evo_data(push, or_config);
Ben Skeggs78951d22011-11-11 18:13:13 +10001021 evo_kick(push, dev, 0);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001022 }
1023
1024 nv_encoder->crtc = encoder->crtc;
1025}
1026
1027static void
1028nvd0_sor_disconnect(struct drm_encoder *encoder)
1029{
1030 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1031 struct drm_device *dev = encoder->dev;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001032 u32 *push;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001033
1034 if (nv_encoder->crtc) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10001035 nvd0_crtc_prepare(nv_encoder->crtc);
1036
1037 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001038 if (push) {
1039 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
1040 evo_data(push, 0x00000000);
1041 evo_mthd(push, 0x0080, 1);
1042 evo_data(push, 0x00000000);
1043 evo_kick(push, dev, 0);
1044 }
1045
Ben Skeggs78951d22011-11-11 18:13:13 +10001046 nvd0_hdmi_disconnect(encoder);
1047
Ben Skeggs83fc0832011-07-05 13:08:40 +10001048 nv_encoder->crtc = NULL;
1049 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1050 }
1051}
1052
1053static void
1054nvd0_sor_destroy(struct drm_encoder *encoder)
1055{
1056 drm_encoder_cleanup(encoder);
1057 kfree(encoder);
1058}
1059
1060static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = {
1061 .dpms = nvd0_sor_dpms,
1062 .mode_fixup = nvd0_sor_mode_fixup,
1063 .prepare = nvd0_sor_prepare,
1064 .commit = nvd0_sor_commit,
1065 .mode_set = nvd0_sor_mode_set,
1066 .disable = nvd0_sor_disconnect,
1067 .get_crtc = nvd0_display_crtc_get,
1068};
1069
1070static const struct drm_encoder_funcs nvd0_sor_func = {
1071 .destroy = nvd0_sor_destroy,
1072};
1073
1074static int
1075nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe)
1076{
1077 struct drm_device *dev = connector->dev;
1078 struct nouveau_encoder *nv_encoder;
1079 struct drm_encoder *encoder;
1080
1081 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
1082 if (!nv_encoder)
1083 return -ENOMEM;
1084 nv_encoder->dcb = dcbe;
1085 nv_encoder->or = ffs(dcbe->or) - 1;
1086 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1087
1088 encoder = to_drm_encoder(nv_encoder);
1089 encoder->possible_crtcs = dcbe->heads;
1090 encoder->possible_clones = 0;
1091 drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS);
1092 drm_encoder_helper_add(encoder, &nvd0_sor_hfunc);
1093
1094 drm_mode_connector_attach_encoder(connector, encoder);
1095 return 0;
1096}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001097
1098/******************************************************************************
1099 * IRQ
1100 *****************************************************************************/
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001101static struct dcb_entry *
1102lookup_dcb(struct drm_device *dev, int id, u32 mc)
1103{
1104 struct drm_nouveau_private *dev_priv = dev->dev_private;
1105 int type, or, i;
1106
1107 if (id < 4) {
1108 type = OUTPUT_ANALOG;
1109 or = id;
1110 } else {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001111 switch (mc & 0x00000f00) {
1112 case 0x00000000: type = OUTPUT_LVDS; break;
1113 case 0x00000100: type = OUTPUT_TMDS; break;
1114 case 0x00000200: type = OUTPUT_TMDS; break;
1115 case 0x00000500: type = OUTPUT_TMDS; break;
1116 default:
Ben Skeggsee417792011-07-08 14:34:45 +10001117 NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001118 return NULL;
1119 }
1120
1121 or = id - 4;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001122 }
1123
1124 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
1125 struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
1126 if (dcb->type == type && (dcb->or & (1 << or)))
1127 return dcb;
1128 }
1129
Ben Skeggsee417792011-07-08 14:34:45 +10001130 NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001131 return NULL;
1132}
1133
Ben Skeggs46005222011-07-05 11:01:13 +10001134static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001135nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001136{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001137 struct dcb_entry *dcb;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001138 int i;
1139
Ben Skeggsee417792011-07-08 14:34:45 +10001140 for (i = 0; mask && i < 8; i++) {
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001141 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
Ben Skeggsee417792011-07-08 14:34:45 +10001142 if (!(mcc & (1 << crtc)))
1143 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001144
Ben Skeggsee417792011-07-08 14:34:45 +10001145 dcb = lookup_dcb(dev, i, mcc);
1146 if (!dcb)
1147 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001148
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001149 nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001150 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001151
Ben Skeggs270a5742011-07-05 14:16:05 +10001152 nv_wr32(dev, 0x6101d4, 0x00000000);
1153 nv_wr32(dev, 0x6109d4, 0x00000000);
1154 nv_wr32(dev, 0x6101d0, 0x80000000);
1155}
1156
1157static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001158nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001159{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001160 struct dcb_entry *dcb;
Ben Skeggs37b034a2011-07-08 14:43:19 +10001161 u32 or, tmp, pclk;
Ben Skeggsee417792011-07-08 14:34:45 +10001162 int i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001163
Ben Skeggsee417792011-07-08 14:34:45 +10001164 for (i = 0; mask && i < 8; i++) {
1165 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
1166 if (!(mcc & (1 << crtc)))
1167 continue;
1168
1169 dcb = lookup_dcb(dev, i, mcc);
1170 if (!dcb)
1171 continue;
1172
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001173 nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001174 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001175
Ben Skeggsee417792011-07-08 14:34:45 +10001176 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
1177 if (mask & 0x00010000) {
1178 nv50_crtc_set_clock(dev, crtc, pclk);
1179 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001180
Ben Skeggsee417792011-07-08 14:34:45 +10001181 for (i = 0; mask && i < 8; i++) {
1182 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1183 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1184 if (!(mcp & (1 << crtc)))
1185 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001186
Ben Skeggsee417792011-07-08 14:34:45 +10001187 dcb = lookup_dcb(dev, i, mcp);
1188 if (!dcb)
1189 continue;
1190 or = ffs(dcb->or) - 1;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001191
Ben Skeggsee417792011-07-08 14:34:45 +10001192 nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001193
Ben Skeggsee417792011-07-08 14:34:45 +10001194 nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000);
1195 switch (dcb->type) {
1196 case OUTPUT_ANALOG:
1197 nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000);
1198 break;
1199 case OUTPUT_TMDS:
1200 case OUTPUT_LVDS:
1201 if (cfg & 0x00000100)
1202 tmp = 0x00000101;
1203 else
1204 tmp = 0x00000000;
1205
1206 nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
1207 break;
1208 default:
1209 break;
1210 }
1211
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001212 break;
1213 }
1214
Ben Skeggs270a5742011-07-05 14:16:05 +10001215 nv_wr32(dev, 0x6101d4, 0x00000000);
1216 nv_wr32(dev, 0x6109d4, 0x00000000);
1217 nv_wr32(dev, 0x6101d0, 0x80000000);
1218}
1219
1220static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001221nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001222{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001223 struct dcb_entry *dcb;
Ben Skeggsee417792011-07-08 14:34:45 +10001224 int pclk, i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001225
Ben Skeggsee417792011-07-08 14:34:45 +10001226 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001227
Ben Skeggsee417792011-07-08 14:34:45 +10001228 for (i = 0; mask && i < 8; i++) {
1229 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1230 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1231 if (!(mcp & (1 << crtc)))
1232 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001233
Ben Skeggsee417792011-07-08 14:34:45 +10001234 dcb = lookup_dcb(dev, i, mcp);
1235 if (!dcb)
1236 continue;
1237
1238 nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc);
1239 }
1240
Ben Skeggs270a5742011-07-05 14:16:05 +10001241 nv_wr32(dev, 0x6101d4, 0x00000000);
1242 nv_wr32(dev, 0x6109d4, 0x00000000);
1243 nv_wr32(dev, 0x6101d0, 0x80000000);
1244}
1245
1246static void
Ben Skeggsf20ce962011-07-08 13:17:01 +10001247nvd0_display_bh(unsigned long data)
1248{
1249 struct drm_device *dev = (struct drm_device *)data;
1250 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001251 u32 mask, crtc;
1252 int i;
1253
1254 if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
1255 NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset);
1256 NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n",
1257 nv_rd32(dev, 0x6101d0),
1258 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
1259 for (i = 0; i < 8; i++) {
1260 NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n",
1261 i < 4 ? "DAC" : "SOR", i,
1262 nv_rd32(dev, 0x640180 + (i * 0x20)),
1263 nv_rd32(dev, 0x660180 + (i * 0x20)));
1264 }
1265 }
1266
1267 mask = nv_rd32(dev, 0x6101d4);
1268 crtc = 0;
1269 if (!mask) {
1270 mask = nv_rd32(dev, 0x6109d4);
1271 crtc = 1;
1272 }
Ben Skeggsf20ce962011-07-08 13:17:01 +10001273
Ben Skeggsee417792011-07-08 14:34:45 +10001274 if (disp->modeset & 0x00000001)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001275 nvd0_display_unk1_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001276 if (disp->modeset & 0x00000002)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001277 nvd0_display_unk2_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001278 if (disp->modeset & 0x00000004)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001279 nvd0_display_unk4_handler(dev, crtc, mask);
Ben Skeggsf20ce962011-07-08 13:17:01 +10001280}
1281
1282static void
Ben Skeggs46005222011-07-05 11:01:13 +10001283nvd0_display_intr(struct drm_device *dev)
1284{
Ben Skeggsf20ce962011-07-08 13:17:01 +10001285 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001286 u32 intr = nv_rd32(dev, 0x610088);
1287
1288 if (intr & 0x00000002) {
1289 u32 stat = nv_rd32(dev, 0x61009c);
1290 int chid = ffs(stat) - 1;
1291 if (chid >= 0) {
1292 u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12));
1293 u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12));
1294 u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12));
1295
1296 NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x "
1297 "0x%08x 0x%08x\n",
1298 chid, (mthd & 0x0000ffc), data, mthd, unkn);
1299 nv_wr32(dev, 0x61009c, (1 << chid));
1300 nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000);
1301 }
1302
1303 intr &= ~0x00000002;
1304 }
1305
Ben Skeggs270a5742011-07-05 14:16:05 +10001306 if (intr & 0x00100000) {
1307 u32 stat = nv_rd32(dev, 0x6100ac);
1308
1309 if (stat & 0x00000007) {
Ben Skeggsee417792011-07-08 14:34:45 +10001310 disp->modeset = stat;
Ben Skeggsf20ce962011-07-08 13:17:01 +10001311 tasklet_schedule(&disp->tasklet);
Ben Skeggs270a5742011-07-05 14:16:05 +10001312
Ben Skeggsf20ce962011-07-08 13:17:01 +10001313 nv_wr32(dev, 0x6100ac, (stat & 0x00000007));
Ben Skeggs270a5742011-07-05 14:16:05 +10001314 stat &= ~0x00000007;
1315 }
1316
1317 if (stat) {
1318 NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat);
1319 nv_wr32(dev, 0x6100ac, stat);
1320 }
1321
1322 intr &= ~0x00100000;
1323 }
1324
Ben Skeggs46005222011-07-05 11:01:13 +10001325 if (intr & 0x01000000) {
1326 u32 stat = nv_rd32(dev, 0x6100bc);
1327 nv_wr32(dev, 0x6100bc, stat);
1328 intr &= ~0x01000000;
1329 }
1330
1331 if (intr & 0x02000000) {
1332 u32 stat = nv_rd32(dev, 0x6108bc);
1333 nv_wr32(dev, 0x6108bc, stat);
1334 intr &= ~0x02000000;
1335 }
1336
1337 if (intr)
1338 NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr);
1339}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001340
1341/******************************************************************************
1342 * Init
1343 *****************************************************************************/
Ben Skeggs2a44e492011-11-09 11:36:33 +10001344void
Ben Skeggs26f6d882011-07-04 16:25:18 +10001345nvd0_display_fini(struct drm_device *dev)
1346{
1347 int i;
1348
1349 /* fini cursors */
1350 for (i = 14; i >= 13; i--) {
1351 if (!(nv_rd32(dev, 0x610490 + (i * 0x10)) & 0x00000001))
1352 continue;
1353
1354 nv_mask(dev, 0x610490 + (i * 0x10), 0x00000001, 0x00000000);
1355 nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00000000);
1356 nv_mask(dev, 0x610090, 1 << i, 0x00000000);
1357 nv_mask(dev, 0x6100a0, 1 << i, 0x00000000);
1358 }
1359
1360 /* fini master */
1361 if (nv_rd32(dev, 0x610490) & 0x00000010) {
1362 nv_mask(dev, 0x610490, 0x00000010, 0x00000000);
1363 nv_mask(dev, 0x610490, 0x00000003, 0x00000000);
1364 nv_wait(dev, 0x610490, 0x80000000, 0x00000000);
1365 nv_mask(dev, 0x610090, 0x00000001, 0x00000000);
1366 nv_mask(dev, 0x6100a0, 0x00000001, 0x00000000);
1367 }
1368}
1369
1370int
1371nvd0_display_init(struct drm_device *dev)
1372{
1373 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001374 u32 *push;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001375 int i;
1376
1377 if (nv_rd32(dev, 0x6100ac) & 0x00000100) {
1378 nv_wr32(dev, 0x6100ac, 0x00000100);
1379 nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000);
1380 if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) {
1381 NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n",
1382 nv_rd32(dev, 0x6194e8));
1383 return -EBUSY;
1384 }
1385 }
1386
Ben Skeggsa36f04c2011-07-06 14:39:23 +10001387 /* nfi what these are exactly, i do know that SOR_MODE_CTRL won't
1388 * work at all unless you do the SOR part below.
1389 */
1390 for (i = 0; i < 3; i++) {
1391 u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800));
1392 nv_wr32(dev, 0x6101c0 + (i * 0x800), dac);
1393 }
1394
1395 for (i = 0; i < 4; i++) {
1396 u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800));
1397 nv_wr32(dev, 0x6301c4 + (i * 0x800), sor);
1398 }
1399
1400 for (i = 0; i < 2; i++) {
1401 u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800));
1402 u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800));
1403 u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800));
1404 nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0);
1405 nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1);
1406 nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2);
1407 }
1408
1409 /* point at our hash table / objects, enable interrupts */
Ben Skeggs26f6d882011-07-04 16:25:18 +10001410 nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9);
Ben Skeggs270a5742011-07-05 14:16:05 +10001411 nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001412
1413 /* init master */
Ben Skeggs51beb422011-07-05 10:33:08 +10001414 nv_wr32(dev, 0x610494, (disp->evo[0].handle >> 8) | 3);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001415 nv_wr32(dev, 0x610498, 0x00010000);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001416 nv_wr32(dev, 0x61049c, 0x00000001);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001417 nv_mask(dev, 0x610490, 0x00000010, 0x00000010);
1418 nv_wr32(dev, 0x640000, 0x00000000);
1419 nv_wr32(dev, 0x610490, 0x01000013);
1420 if (!nv_wait(dev, 0x610490, 0x80000000, 0x00000000)) {
1421 NV_ERROR(dev, "PDISP: master 0x%08x\n",
1422 nv_rd32(dev, 0x610490));
1423 return -EBUSY;
1424 }
1425 nv_mask(dev, 0x610090, 0x00000001, 0x00000001);
1426 nv_mask(dev, 0x6100a0, 0x00000001, 0x00000001);
1427
1428 /* init cursors */
1429 for (i = 13; i <= 14; i++) {
1430 nv_wr32(dev, 0x610490 + (i * 0x10), 0x00000001);
1431 if (!nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00010000)) {
1432 NV_ERROR(dev, "PDISP: curs%d 0x%08x\n", i,
1433 nv_rd32(dev, 0x610490 + (i * 0x10)));
1434 return -EBUSY;
1435 }
1436
1437 nv_mask(dev, 0x610090, 1 << i, 1 << i);
1438 nv_mask(dev, 0x6100a0, 1 << i, 1 << i);
1439 }
1440
Ben Skeggsefd272a2011-07-05 11:58:58 +10001441 push = evo_wait(dev, 0, 32);
1442 if (!push)
1443 return -EBUSY;
1444 evo_mthd(push, 0x0088, 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001445 evo_data(push, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001446 evo_mthd(push, 0x0084, 1);
1447 evo_data(push, 0x00000000);
1448 evo_mthd(push, 0x0084, 1);
1449 evo_data(push, 0x80000000);
1450 evo_mthd(push, 0x008c, 1);
1451 evo_data(push, 0x00000000);
1452 evo_kick(push, dev, 0);
1453
Ben Skeggs26f6d882011-07-04 16:25:18 +10001454 return 0;
1455}
1456
1457void
1458nvd0_display_destroy(struct drm_device *dev)
1459{
1460 struct drm_nouveau_private *dev_priv = dev->dev_private;
1461 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs51beb422011-07-05 10:33:08 +10001462 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001463
Ben Skeggs51beb422011-07-05 10:33:08 +10001464 pci_free_consistent(pdev, PAGE_SIZE, disp->evo[0].ptr, disp->evo[0].handle);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001465 nouveau_gpuobj_ref(NULL, &disp->mem);
Ben Skeggs46005222011-07-05 11:01:13 +10001466 nouveau_irq_unregister(dev, 26);
Ben Skeggs51beb422011-07-05 10:33:08 +10001467
1468 dev_priv->engine.display.priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001469 kfree(disp);
1470}
1471
1472int
1473nvd0_display_create(struct drm_device *dev)
1474{
1475 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsefd272a2011-07-05 11:58:58 +10001476 struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001477 struct dcb_table *dcb = &dev_priv->vbios.dcb;
1478 struct drm_connector *connector, *tmp;
Ben Skeggs51beb422011-07-05 10:33:08 +10001479 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001480 struct nvd0_display *disp;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001481 struct dcb_entry *dcbe;
1482 int ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001483
1484 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
1485 if (!disp)
1486 return -ENOMEM;
1487 dev_priv->engine.display.priv = disp;
1488
Ben Skeggs438d99e2011-07-05 16:48:06 +10001489 /* create crtc objects to represent the hw heads */
1490 for (i = 0; i < 2; i++) {
1491 ret = nvd0_crtc_create(dev, i);
1492 if (ret)
1493 goto out;
1494 }
1495
Ben Skeggs83fc0832011-07-05 13:08:40 +10001496 /* create encoder/connector objects based on VBIOS DCB table */
1497 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
1498 connector = nouveau_connector_create(dev, dcbe->connector);
1499 if (IS_ERR(connector))
1500 continue;
1501
1502 if (dcbe->location != DCB_LOC_ON_CHIP) {
1503 NV_WARN(dev, "skipping off-chip encoder %d/%d\n",
1504 dcbe->type, ffs(dcbe->or) - 1);
1505 continue;
1506 }
1507
1508 switch (dcbe->type) {
1509 case OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001510 case OUTPUT_LVDS:
Ben Skeggs83fc0832011-07-05 13:08:40 +10001511 nvd0_sor_create(connector, dcbe);
1512 break;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001513 case OUTPUT_ANALOG:
1514 nvd0_dac_create(connector, dcbe);
1515 break;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001516 default:
1517 NV_WARN(dev, "skipping unsupported encoder %d/%d\n",
1518 dcbe->type, ffs(dcbe->or) - 1);
1519 continue;
1520 }
1521 }
1522
1523 /* cull any connectors we created that don't have an encoder */
1524 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
1525 if (connector->encoder_ids[0])
1526 continue;
1527
1528 NV_WARN(dev, "%s has no encoders, removing\n",
1529 drm_get_connector_name(connector));
1530 connector->funcs->destroy(connector);
1531 }
1532
Ben Skeggs46005222011-07-05 11:01:13 +10001533 /* setup interrupt handling */
Ben Skeggsf20ce962011-07-08 13:17:01 +10001534 tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001535 nouveau_irq_register(dev, 26, nvd0_display_intr);
1536
Ben Skeggs51beb422011-07-05 10:33:08 +10001537 /* hash table and dma objects for the memory areas we care about */
Ben Skeggsefd272a2011-07-05 11:58:58 +10001538 ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000,
1539 NVOBJ_FLAG_ZERO_ALLOC, &disp->mem);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001540 if (ret)
1541 goto out;
1542
Ben Skeggsefd272a2011-07-05 11:58:58 +10001543 nv_wo32(disp->mem, 0x1000, 0x00000049);
1544 nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8);
1545 nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8);
1546 nv_wo32(disp->mem, 0x100c, 0x00000000);
1547 nv_wo32(disp->mem, 0x1010, 0x00000000);
1548 nv_wo32(disp->mem, 0x1014, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001549 nv_wo32(disp->mem, 0x0000, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001550 nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001);
1551
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001552 nv_wo32(disp->mem, 0x1020, 0x00000049);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001553 nv_wo32(disp->mem, 0x1024, 0x00000000);
1554 nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8);
1555 nv_wo32(disp->mem, 0x102c, 0x00000000);
1556 nv_wo32(disp->mem, 0x1030, 0x00000000);
1557 nv_wo32(disp->mem, 0x1034, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001558 nv_wo32(disp->mem, 0x0008, NvEvoVRAM);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001559 nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001);
1560
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001561 nv_wo32(disp->mem, 0x1040, 0x00000009);
1562 nv_wo32(disp->mem, 0x1044, 0x00000000);
1563 nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8);
1564 nv_wo32(disp->mem, 0x104c, 0x00000000);
1565 nv_wo32(disp->mem, 0x1050, 0x00000000);
1566 nv_wo32(disp->mem, 0x1054, 0x00000000);
1567 nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP);
1568 nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001);
1569
1570 nv_wo32(disp->mem, 0x1060, 0x0fe00009);
1571 nv_wo32(disp->mem, 0x1064, 0x00000000);
1572 nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8);
1573 nv_wo32(disp->mem, 0x106c, 0x00000000);
1574 nv_wo32(disp->mem, 0x1070, 0x00000000);
1575 nv_wo32(disp->mem, 0x1074, 0x00000000);
1576 nv_wo32(disp->mem, 0x0018, NvEvoFB32);
1577 nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001);
1578
Ben Skeggsefd272a2011-07-05 11:58:58 +10001579 pinstmem->flush(dev);
1580
Ben Skeggs51beb422011-07-05 10:33:08 +10001581 /* push buffers for evo channels */
1582 disp->evo[0].ptr =
1583 pci_alloc_consistent(pdev, PAGE_SIZE, &disp->evo[0].handle);
1584 if (!disp->evo[0].ptr) {
1585 ret = -ENOMEM;
1586 goto out;
1587 }
1588
Ben Skeggs26f6d882011-07-04 16:25:18 +10001589out:
1590 if (ret)
1591 nvd0_display_destroy(dev);
1592 return ret;
1593}