blob: a54f96751e1fd0c18cdc164b483e4d6c2d606545 [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
87 return disp->evo[id].ptr + put;
88}
89
90static void
91evo_kick(u32 *push, struct drm_device *dev, int id)
92{
93 struct nvd0_display *disp = nvd0_display(dev);
94 nv_wr32(dev, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2);
95}
96
97#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
98#define evo_data(p,d) *((p)++) = (d)
99
Ben Skeggs83fc0832011-07-05 13:08:40 +1000100static struct drm_crtc *
101nvd0_display_crtc_get(struct drm_encoder *encoder)
102{
103 return nouveau_encoder(encoder)->crtc;
104}
105
Ben Skeggs26f6d882011-07-04 16:25:18 +1000106/******************************************************************************
Ben Skeggs438d99e2011-07-05 16:48:06 +1000107 * CRTC
108 *****************************************************************************/
109static int
Ben Skeggs488ff202011-10-17 10:38:10 +1000110nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000111{
112 struct drm_device *dev = nv_crtc->base.dev;
Ben Skeggsde691852011-10-17 12:23:41 +1000113 struct nouveau_connector *nv_connector;
114 struct drm_connector *connector;
115 u32 *push, mode = 0x00;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000116
Ben Skeggs488ff202011-10-17 10:38:10 +1000117 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsde691852011-10-17 12:23:41 +1000118 connector = &nv_connector->base;
119 if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
120 if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
121 mode = DITHERING_MODE_DYNAMIC2X2;
122 } else {
123 mode = nv_connector->dithering_mode;
124 }
125
126 if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) {
127 if (connector->display_info.bpc >= 8)
128 mode |= DITHERING_DEPTH_8BPC;
129 } else {
130 mode |= nv_connector->dithering_depth;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000131 }
132
133 push = evo_wait(dev, 0, 4);
134 if (push) {
135 evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1);
136 evo_data(push, mode);
137 if (update) {
138 evo_mthd(push, 0x0080, 1);
139 evo_data(push, 0x00000000);
140 }
141 evo_kick(push, dev, 0);
142 }
143
144 return 0;
145}
146
147static int
Ben Skeggs488ff202011-10-17 10:38:10 +1000148nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000149{
150 struct drm_display_mode *mode = &nv_crtc->base.mode;
151 struct drm_device *dev = nv_crtc->base.dev;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000152 struct nouveau_connector *nv_connector;
153 u32 *push, outX, outY;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000154
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000155 outX = mode->hdisplay;
156 outY = mode->vdisplay;
157
158 nv_connector = nouveau_crtc_connector_get(nv_crtc);
159 if (nv_connector && nv_connector->native_mode) {
160 struct drm_display_mode *native = nv_connector->native_mode;
161 u32 xratio = (native->hdisplay << 19) / mode->hdisplay;
162 u32 yratio = (native->vdisplay << 19) / mode->vdisplay;
163
Ben Skeggs488ff202011-10-17 10:38:10 +1000164 switch (nv_connector->scaling_mode) {
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000165 case DRM_MODE_SCALE_ASPECT:
166 if (xratio > yratio) {
167 outX = (mode->hdisplay * yratio) >> 19;
168 outY = (mode->vdisplay * yratio) >> 19;
169 } else {
170 outX = (mode->hdisplay * xratio) >> 19;
171 outY = (mode->vdisplay * xratio) >> 19;
172 }
173 break;
174 case DRM_MODE_SCALE_FULLSCREEN:
175 outX = native->hdisplay;
176 outY = native->vdisplay;
177 break;
178 default:
179 break;
180 }
181 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000182
183 push = evo_wait(dev, 0, 16);
184 if (push) {
185 evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000186 evo_data(push, (outY << 16) | outX);
187 evo_data(push, (outY << 16) | outX);
188 evo_data(push, (outY << 16) | outX);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000189 evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
190 evo_data(push, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000191 evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
192 evo_data(push, (mode->vdisplay << 16) | mode->hdisplay);
193 if (update) {
194 evo_mthd(push, 0x0080, 1);
195 evo_data(push, 0x00000000);
196 }
197 evo_kick(push, dev, 0);
198 }
199
200 return 0;
201}
202
203static int
204nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
205 int x, int y, bool update)
206{
207 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
208 u32 *push;
209
Ben Skeggs438d99e2011-07-05 16:48:06 +1000210 push = evo_wait(fb->dev, 0, 16);
211 if (push) {
212 evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1);
213 evo_data(push, nvfb->nvbo->bo.offset >> 8);
214 evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4);
215 evo_data(push, (fb->height << 16) | fb->width);
216 evo_data(push, nvfb->r_pitch);
217 evo_data(push, nvfb->r_format);
Ben Skeggsc0cc92a2011-07-06 11:40:45 +1000218 evo_data(push, nvfb->r_dma);
Ben Skeggsc6f2f712011-07-08 12:11:58 +1000219 evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1);
220 evo_data(push, (y << 16) | x);
Ben Skeggsa46232e2011-07-07 15:23:48 +1000221 if (update) {
222 evo_mthd(push, 0x0080, 1);
223 evo_data(push, 0x00000000);
224 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000225 evo_kick(push, fb->dev, 0);
226 }
227
Ben Skeggsc0cc92a2011-07-06 11:40:45 +1000228 nv_crtc->fb.tile_flags = nvfb->r_dma;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000229 return 0;
230}
231
232static void
233nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update)
234{
235 struct drm_device *dev = nv_crtc->base.dev;
236 u32 *push = evo_wait(dev, 0, 16);
237 if (push) {
238 if (show) {
239 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
240 evo_data(push, 0x85000000);
241 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
242 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +1000243 evo_data(push, NvEvoVRAM);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000244 } else {
245 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1);
246 evo_data(push, 0x05000000);
247 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
248 evo_data(push, 0x00000000);
249 }
250
251 if (update) {
252 evo_mthd(push, 0x0080, 1);
253 evo_data(push, 0x00000000);
254 }
255
256 evo_kick(push, dev, 0);
257 }
258}
259
260static void
261nvd0_crtc_dpms(struct drm_crtc *crtc, int mode)
262{
263}
264
265static void
266nvd0_crtc_prepare(struct drm_crtc *crtc)
267{
268 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
269 u32 *push;
270
271 push = evo_wait(crtc->dev, 0, 2);
272 if (push) {
273 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
274 evo_data(push, 0x00000000);
275 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1);
276 evo_data(push, 0x03000000);
277 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
278 evo_data(push, 0x00000000);
279 evo_kick(push, crtc->dev, 0);
280 }
281
282 nvd0_crtc_cursor_show(nv_crtc, false, false);
283}
284
285static void
286nvd0_crtc_commit(struct drm_crtc *crtc)
287{
288 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
289 u32 *push;
290
291 push = evo_wait(crtc->dev, 0, 32);
292 if (push) {
293 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
294 evo_data(push, nv_crtc->fb.tile_flags);
295 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4);
296 evo_data(push, 0x83000000);
297 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
298 evo_data(push, 0x00000000);
299 evo_data(push, 0x00000000);
300 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +1000301 evo_data(push, NvEvoVRAM);
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000302 evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1);
303 evo_data(push, 0xffffff00);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000304 evo_kick(push, crtc->dev, 0);
305 }
306
307 nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true);
308}
309
310static bool
311nvd0_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
312 struct drm_display_mode *adjusted_mode)
313{
314 return true;
315}
316
317static int
318nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
319{
320 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
321 int ret;
322
323 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
324 if (ret)
325 return ret;
326
327 if (old_fb) {
328 nvfb = nouveau_framebuffer(old_fb);
329 nouveau_bo_unpin(nvfb->nvbo);
330 }
331
332 return 0;
333}
334
335static int
336nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
337 struct drm_display_mode *mode, int x, int y,
338 struct drm_framebuffer *old_fb)
339{
340 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
341 struct nouveau_connector *nv_connector;
342 u32 htotal = mode->htotal;
343 u32 vtotal = mode->vtotal;
344 u32 hsyncw = mode->hsync_end - mode->hsync_start - 1;
345 u32 vsyncw = mode->vsync_end - mode->vsync_start - 1;
346 u32 hfrntp = mode->hsync_start - mode->hdisplay;
347 u32 vfrntp = mode->vsync_start - mode->vdisplay;
348 u32 hbackp = mode->htotal - mode->hsync_end;
349 u32 vbackp = mode->vtotal - mode->vsync_end;
350 u32 hss2be = hsyncw + hbackp;
351 u32 vss2be = vsyncw + vbackp;
352 u32 hss2de = htotal - hfrntp;
353 u32 vss2de = vtotal - vfrntp;
Ben Skeggs629c1b92011-07-08 09:43:20 +1000354 u32 syncs, *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000355 int ret;
356
Ben Skeggs629c1b92011-07-08 09:43:20 +1000357 syncs = 0x00000001;
358 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
359 syncs |= 0x00000008;
360 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
361 syncs |= 0x00000010;
362
Ben Skeggs438d99e2011-07-05 16:48:06 +1000363 ret = nvd0_crtc_swap_fbs(crtc, old_fb);
364 if (ret)
365 return ret;
366
367 push = evo_wait(crtc->dev, 0, 64);
368 if (push) {
369 evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 5);
Ben Skeggs629c1b92011-07-08 09:43:20 +1000370 evo_data(push, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000371 evo_data(push, (vtotal << 16) | htotal);
372 evo_data(push, (vsyncw << 16) | hsyncw);
373 evo_data(push, (vss2be << 16) | hss2be);
374 evo_data(push, (vss2de << 16) | hss2de);
375 evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1);
376 evo_data(push, 0x00000000); /* ??? */
377 evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3);
378 evo_data(push, mode->clock * 1000);
379 evo_data(push, 0x00200000); /* ??? */
380 evo_data(push, mode->clock * 1000);
Ben Skeggs629c1b92011-07-08 09:43:20 +1000381 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 1);
382 evo_data(push, syncs);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000383 evo_kick(push, crtc->dev, 0);
384 }
385
386 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggs488ff202011-10-17 10:38:10 +1000387 nvd0_crtc_set_dither(nv_crtc, false);
388 nvd0_crtc_set_scale(nv_crtc, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000389 nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
390 return 0;
391}
392
393static int
394nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
395 struct drm_framebuffer *old_fb)
396{
397 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
398 int ret;
399
Ben Skeggs84e2ad82011-08-26 09:40:39 +1000400 if (!crtc->fb) {
401 NV_DEBUG_KMS(crtc->dev, "No FB bound\n");
402 return 0;
403 }
404
Ben Skeggs438d99e2011-07-05 16:48:06 +1000405 ret = nvd0_crtc_swap_fbs(crtc, old_fb);
406 if (ret)
407 return ret;
408
409 nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
410 return 0;
411}
412
413static int
414nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
415 struct drm_framebuffer *fb, int x, int y,
416 enum mode_set_atomic state)
417{
418 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
419 nvd0_crtc_set_image(nv_crtc, fb, x, y, true);
420 return 0;
421}
422
423static void
424nvd0_crtc_lut_load(struct drm_crtc *crtc)
425{
426 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
427 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
428 int i;
429
430 for (i = 0; i < 256; i++) {
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000431 writew(0x6000 + (nv_crtc->lut.r[i] >> 2), lut + (i * 0x20) + 0);
432 writew(0x6000 + (nv_crtc->lut.g[i] >> 2), lut + (i * 0x20) + 2);
433 writew(0x6000 + (nv_crtc->lut.b[i] >> 2), lut + (i * 0x20) + 4);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000434 }
435}
436
437static int
438nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
439 uint32_t handle, uint32_t width, uint32_t height)
440{
441 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
442 struct drm_device *dev = crtc->dev;
443 struct drm_gem_object *gem;
444 struct nouveau_bo *nvbo;
445 bool visible = (handle != 0);
446 int i, ret = 0;
447
448 if (visible) {
449 if (width != 64 || height != 64)
450 return -EINVAL;
451
452 gem = drm_gem_object_lookup(dev, file_priv, handle);
453 if (unlikely(!gem))
454 return -ENOENT;
455 nvbo = nouveau_gem_object(gem);
456
457 ret = nouveau_bo_map(nvbo);
458 if (ret == 0) {
459 for (i = 0; i < 64 * 64; i++) {
460 u32 v = nouveau_bo_rd32(nvbo, i);
461 nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v);
462 }
463 nouveau_bo_unmap(nvbo);
464 }
465
466 drm_gem_object_unreference_unlocked(gem);
467 }
468
469 if (visible != nv_crtc->cursor.visible) {
470 nvd0_crtc_cursor_show(nv_crtc, visible, true);
471 nv_crtc->cursor.visible = visible;
472 }
473
474 return ret;
475}
476
477static int
478nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
479{
480 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
481 const u32 data = (y << 16) | x;
482
483 nv_wr32(crtc->dev, 0x64d084 + (nv_crtc->index * 0x1000), data);
484 nv_wr32(crtc->dev, 0x64d080 + (nv_crtc->index * 0x1000), 0x00000000);
485 return 0;
486}
487
488static void
489nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
490 uint32_t start, uint32_t size)
491{
492 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
493 u32 end = max(start + size, (u32)256);
494 u32 i;
495
496 for (i = start; i < end; i++) {
497 nv_crtc->lut.r[i] = r[i];
498 nv_crtc->lut.g[i] = g[i];
499 nv_crtc->lut.b[i] = b[i];
500 }
501
502 nvd0_crtc_lut_load(crtc);
503}
504
505static void
506nvd0_crtc_destroy(struct drm_crtc *crtc)
507{
508 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
509 nouveau_bo_unmap(nv_crtc->cursor.nvbo);
510 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
511 nouveau_bo_unmap(nv_crtc->lut.nvbo);
512 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
513 drm_crtc_cleanup(crtc);
514 kfree(crtc);
515}
516
517static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = {
518 .dpms = nvd0_crtc_dpms,
519 .prepare = nvd0_crtc_prepare,
520 .commit = nvd0_crtc_commit,
521 .mode_fixup = nvd0_crtc_mode_fixup,
522 .mode_set = nvd0_crtc_mode_set,
523 .mode_set_base = nvd0_crtc_mode_set_base,
524 .mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic,
525 .load_lut = nvd0_crtc_lut_load,
526};
527
528static const struct drm_crtc_funcs nvd0_crtc_func = {
529 .cursor_set = nvd0_crtc_cursor_set,
530 .cursor_move = nvd0_crtc_cursor_move,
531 .gamma_set = nvd0_crtc_gamma_set,
532 .set_config = drm_crtc_helper_set_config,
533 .destroy = nvd0_crtc_destroy,
534};
535
Ben Skeggsc20ab3e2011-08-25 14:09:43 +1000536static void
537nvd0_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
538{
539}
540
541static void
542nvd0_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
543{
544}
545
Ben Skeggs438d99e2011-07-05 16:48:06 +1000546static int
547nvd0_crtc_create(struct drm_device *dev, int index)
548{
549 struct nouveau_crtc *nv_crtc;
550 struct drm_crtc *crtc;
551 int ret, i;
552
553 nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
554 if (!nv_crtc)
555 return -ENOMEM;
556
557 nv_crtc->index = index;
558 nv_crtc->set_dither = nvd0_crtc_set_dither;
559 nv_crtc->set_scale = nvd0_crtc_set_scale;
Ben Skeggsc20ab3e2011-08-25 14:09:43 +1000560 nv_crtc->cursor.set_offset = nvd0_cursor_set_offset;
561 nv_crtc->cursor.set_pos = nvd0_cursor_set_pos;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000562 for (i = 0; i < 256; i++) {
563 nv_crtc->lut.r[i] = i << 8;
564 nv_crtc->lut.g[i] = i << 8;
565 nv_crtc->lut.b[i] = i << 8;
566 }
567
568 crtc = &nv_crtc->base;
569 drm_crtc_init(dev, crtc, &nvd0_crtc_func);
570 drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc);
571 drm_mode_crtc_set_gamma_size(crtc, 256);
572
573 ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
574 0, 0x0000, &nv_crtc->cursor.nvbo);
575 if (!ret) {
576 ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
577 if (!ret)
578 ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
579 if (ret)
580 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
581 }
582
583 if (ret)
584 goto out;
585
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000586 ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
Ben Skeggs438d99e2011-07-05 16:48:06 +1000587 0, 0x0000, &nv_crtc->lut.nvbo);
588 if (!ret) {
589 ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
590 if (!ret)
591 ret = nouveau_bo_map(nv_crtc->lut.nvbo);
592 if (ret)
593 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
594 }
595
596 if (ret)
597 goto out;
598
599 nvd0_crtc_lut_load(crtc);
600
601out:
602 if (ret)
603 nvd0_crtc_destroy(crtc);
604 return ret;
605}
606
607/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +1000608 * DAC
609 *****************************************************************************/
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000610static void
611nvd0_dac_dpms(struct drm_encoder *encoder, int mode)
612{
613 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
614 struct drm_device *dev = encoder->dev;
615 int or = nv_encoder->or;
616 u32 dpms_ctrl;
617
618 dpms_ctrl = 0x80000000;
619 if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF)
620 dpms_ctrl |= 0x00000001;
621 if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF)
622 dpms_ctrl |= 0x00000004;
623
624 nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
625 nv_mask(dev, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl);
626 nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
627}
628
629static bool
630nvd0_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
631 struct drm_display_mode *adjusted_mode)
632{
633 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
634 struct nouveau_connector *nv_connector;
635
636 nv_connector = nouveau_encoder_connector_get(nv_encoder);
637 if (nv_connector && nv_connector->native_mode) {
638 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
639 int id = adjusted_mode->base.id;
640 *adjusted_mode = *nv_connector->native_mode;
641 adjusted_mode->base.id = id;
642 }
643 }
644
645 return true;
646}
647
648static void
649nvd0_dac_prepare(struct drm_encoder *encoder)
650{
651}
652
653static void
654nvd0_dac_commit(struct drm_encoder *encoder)
655{
656}
657
658static void
659nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
660 struct drm_display_mode *adjusted_mode)
661{
662 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
663 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
664 u32 *push;
665
666 nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON);
667
Ben Skeggsff8ff502011-07-08 11:53:37 +1000668 push = evo_wait(encoder->dev, 0, 4);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000669 if (push) {
Ben Skeggsff8ff502011-07-08 11:53:37 +1000670 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000671 evo_data(push, 1 << nv_crtc->index);
Ben Skeggsff8ff502011-07-08 11:53:37 +1000672 evo_data(push, 0x00ff);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000673 evo_kick(push, encoder->dev, 0);
674 }
675
676 nv_encoder->crtc = encoder->crtc;
677}
678
679static void
680nvd0_dac_disconnect(struct drm_encoder *encoder)
681{
682 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
683 struct drm_device *dev = encoder->dev;
684 u32 *push;
685
686 if (nv_encoder->crtc) {
687 nvd0_crtc_prepare(nv_encoder->crtc);
688
689 push = evo_wait(dev, 0, 4);
690 if (push) {
691 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 1);
692 evo_data(push, 0x00000000);
693 evo_mthd(push, 0x0080, 1);
694 evo_data(push, 0x00000000);
695 evo_kick(push, dev, 0);
696 }
697
698 nv_encoder->crtc = NULL;
699 }
700}
701
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000702static enum drm_connector_status
703nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
704{
Ben Skeggsb6819932011-07-08 11:14:50 +1000705 enum drm_connector_status status = connector_status_disconnected;
706 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
707 struct drm_device *dev = encoder->dev;
708 int or = nv_encoder->or;
709 u32 load;
710
711 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00100000);
712 udelay(9500);
713 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x80000000);
714
715 load = nv_rd32(dev, 0x61a00c + (or * 0x800));
716 if ((load & 0x38000000) == 0x38000000)
717 status = connector_status_connected;
718
719 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00000000);
720 return status;
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000721}
722
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000723static void
724nvd0_dac_destroy(struct drm_encoder *encoder)
725{
726 drm_encoder_cleanup(encoder);
727 kfree(encoder);
728}
729
730static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = {
731 .dpms = nvd0_dac_dpms,
732 .mode_fixup = nvd0_dac_mode_fixup,
733 .prepare = nvd0_dac_prepare,
734 .commit = nvd0_dac_commit,
735 .mode_set = nvd0_dac_mode_set,
736 .disable = nvd0_dac_disconnect,
737 .get_crtc = nvd0_display_crtc_get,
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000738 .detect = nvd0_dac_detect
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000739};
740
741static const struct drm_encoder_funcs nvd0_dac_func = {
742 .destroy = nvd0_dac_destroy,
743};
744
745static int
746nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe)
747{
748 struct drm_device *dev = connector->dev;
749 struct nouveau_encoder *nv_encoder;
750 struct drm_encoder *encoder;
751
752 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
753 if (!nv_encoder)
754 return -ENOMEM;
755 nv_encoder->dcb = dcbe;
756 nv_encoder->or = ffs(dcbe->or) - 1;
757
758 encoder = to_drm_encoder(nv_encoder);
759 encoder->possible_crtcs = dcbe->heads;
760 encoder->possible_clones = 0;
761 drm_encoder_init(dev, encoder, &nvd0_dac_func, DRM_MODE_ENCODER_DAC);
762 drm_encoder_helper_add(encoder, &nvd0_dac_hfunc);
763
764 drm_mode_connector_attach_encoder(connector, encoder);
765 return 0;
766}
Ben Skeggs26f6d882011-07-04 16:25:18 +1000767
768/******************************************************************************
Ben Skeggs78951d22011-11-11 18:13:13 +1000769 * Audio
770 *****************************************************************************/
771static void
772nvd0_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
773{
774 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
775 struct nouveau_connector *nv_connector;
776 struct drm_device *dev = encoder->dev;
777 int i, or = nv_encoder->or * 0x30;
778
779 nv_connector = nouveau_encoder_connector_get(nv_encoder);
780 if (!drm_detect_monitor_audio(nv_connector->edid))
781 return;
782
783 nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000001);
784
785 drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
786 if (nv_connector->base.eld[0]) {
787 u8 *eld = nv_connector->base.eld;
788
789 for (i = 0; i < eld[2] * 4; i++)
790 nv_wr32(dev, 0x10ec00 + or, (i << 8) | eld[i]);
791 for (i = eld[2] * 4; i < 0x60; i++)
792 nv_wr32(dev, 0x10ec00 + or, (i << 8) | 0x00);
793
794 nv_mask(dev, 0x10ec10 + or, 0x80000002, 0x80000002);
795 }
796}
797
798static void
799nvd0_audio_disconnect(struct drm_encoder *encoder)
800{
801 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
802 struct drm_device *dev = encoder->dev;
803 int or = nv_encoder->or * 0x30;
804
805 nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000000);
806}
807
808/******************************************************************************
809 * HDMI
810 *****************************************************************************/
811static void
812nvd0_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
813{
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000814 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
815 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
816 struct nouveau_connector *nv_connector;
817 struct drm_device *dev = encoder->dev;
818 int head = nv_crtc->index * 0x800;
819 u32 rekey = 56; /* binary driver, and tegra constant */
820 u32 max_ac_packet;
821
822 nv_connector = nouveau_encoder_connector_get(nv_encoder);
823 if (!drm_detect_hdmi_monitor(nv_connector->edid))
824 return;
825
826 max_ac_packet = mode->htotal - mode->hdisplay;
827 max_ac_packet -= rekey;
828 max_ac_packet -= 18; /* constant from tegra */
829 max_ac_packet /= 32;
830
831 /* AVI InfoFrame */
832 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000000);
833 nv_wr32(dev, 0x61671c + head, 0x000d0282);
834 nv_wr32(dev, 0x616720 + head, 0x0000006f);
835 nv_wr32(dev, 0x616724 + head, 0x00000000);
836 nv_wr32(dev, 0x616728 + head, 0x00000000);
837 nv_wr32(dev, 0x61672c + head, 0x00000000);
838 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000001);
839
840 /* ??? InfoFrame? */
841 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000000);
842 nv_wr32(dev, 0x6167ac + head, 0x00000010);
843 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000001);
844
845 /* HDMI_CTRL */
846 nv_mask(dev, 0x616798 + head, 0x401f007f, 0x40000000 | rekey |
847 max_ac_packet << 16);
848
Ben Skeggs78951d22011-11-11 18:13:13 +1000849 nvd0_audio_mode_set(encoder, mode);
850}
851
852static void
853nvd0_hdmi_disconnect(struct drm_encoder *encoder)
854{
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000855 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
856 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
857 struct drm_device *dev = encoder->dev;
858 int head = nv_crtc->index * 0x800;
859
Ben Skeggs78951d22011-11-11 18:13:13 +1000860 nvd0_audio_disconnect(encoder);
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000861
862 nv_mask(dev, 0x616798 + head, 0x40000000, 0x00000000);
863 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000000);
864 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000000);
Ben Skeggs78951d22011-11-11 18:13:13 +1000865}
866
867/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +1000868 * SOR
869 *****************************************************************************/
Ben Skeggs83fc0832011-07-05 13:08:40 +1000870static void
871nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
872{
873 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
874 struct drm_device *dev = encoder->dev;
875 struct drm_encoder *partner;
876 int or = nv_encoder->or;
877 u32 dpms_ctrl;
878
879 nv_encoder->last_dpms = mode;
880
881 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
882 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
883
884 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
885 continue;
886
887 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +1000888 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +1000889 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
890 return;
891 break;
892 }
893 }
894
895 dpms_ctrl = (mode == DRM_MODE_DPMS_ON);
896 dpms_ctrl |= 0x80000000;
897
898 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
899 nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
900 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
901 nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
902}
903
904static bool
905nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
906 struct drm_display_mode *adjusted_mode)
907{
908 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
909 struct nouveau_connector *nv_connector;
910
911 nv_connector = nouveau_encoder_connector_get(nv_encoder);
912 if (nv_connector && nv_connector->native_mode) {
913 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
914 int id = adjusted_mode->base.id;
915 *adjusted_mode = *nv_connector->native_mode;
916 adjusted_mode->base.id = id;
917 }
918 }
919
920 return true;
921}
922
923static void
924nvd0_sor_prepare(struct drm_encoder *encoder)
925{
926}
927
928static void
929nvd0_sor_commit(struct drm_encoder *encoder)
930{
931}
932
933static void
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000934nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
935 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +1000936{
Ben Skeggs78951d22011-11-11 18:13:13 +1000937 struct drm_device *dev = encoder->dev;
938 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000939 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
940 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000941 struct nouveau_connector *nv_connector;
942 struct nvbios *bios = &dev_priv->vbios;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000943 u32 mode_ctrl = (1 << nv_crtc->index);
Ben Skeggsff8ff502011-07-08 11:53:37 +1000944 u32 *push, or_config;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000945
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000946 nv_connector = nouveau_encoder_connector_get(nv_encoder);
947 switch (nv_encoder->dcb->type) {
948 case OUTPUT_TMDS:
949 if (nv_encoder->dcb->sorconf.link & 1) {
950 if (mode->clock < 165000)
951 mode_ctrl |= 0x00000100;
952 else
953 mode_ctrl |= 0x00000500;
954 } else {
955 mode_ctrl |= 0x00000200;
956 }
Ben Skeggs83fc0832011-07-05 13:08:40 +1000957
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000958 or_config = (mode_ctrl & 0x00000f00) >> 8;
959 if (mode->clock >= 165000)
960 or_config |= 0x0100;
Ben Skeggs78951d22011-11-11 18:13:13 +1000961
962 nvd0_hdmi_mode_set(encoder, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000963 break;
964 case OUTPUT_LVDS:
965 or_config = (mode_ctrl & 0x00000f00) >> 8;
966 if (bios->fp_no_ddc) {
967 if (bios->fp.dual_link)
968 or_config |= 0x0100;
969 if (bios->fp.if_is_24bit)
970 or_config |= 0x0200;
971 } else {
972 if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
973 if (((u8 *)nv_connector->edid)[121] == 2)
974 or_config |= 0x0100;
975 } else
976 if (mode->clock >= bios->fp.duallink_transition_clk) {
977 or_config |= 0x0100;
978 }
979
980 if (or_config & 0x0100) {
981 if (bios->fp.strapless_is_24bit & 2)
982 or_config |= 0x0200;
983 } else {
984 if (bios->fp.strapless_is_24bit & 1)
985 or_config |= 0x0200;
986 }
987
988 if (nv_connector->base.display_info.bpc == 8)
989 or_config |= 0x0200;
990
991 }
992 break;
993 default:
994 BUG_ON(1);
995 break;
996 }
Ben Skeggsff8ff502011-07-08 11:53:37 +1000997
Ben Skeggs83fc0832011-07-05 13:08:40 +1000998 nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
999
Ben Skeggs78951d22011-11-11 18:13:13 +10001000 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001001 if (push) {
Ben Skeggsff8ff502011-07-08 11:53:37 +10001002 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001003 evo_data(push, mode_ctrl);
Ben Skeggsff8ff502011-07-08 11:53:37 +10001004 evo_data(push, or_config);
Ben Skeggs78951d22011-11-11 18:13:13 +10001005 evo_kick(push, dev, 0);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001006 }
1007
1008 nv_encoder->crtc = encoder->crtc;
1009}
1010
1011static void
1012nvd0_sor_disconnect(struct drm_encoder *encoder)
1013{
1014 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1015 struct drm_device *dev = encoder->dev;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001016 u32 *push;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001017
1018 if (nv_encoder->crtc) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10001019 nvd0_crtc_prepare(nv_encoder->crtc);
1020
1021 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001022 if (push) {
1023 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
1024 evo_data(push, 0x00000000);
1025 evo_mthd(push, 0x0080, 1);
1026 evo_data(push, 0x00000000);
1027 evo_kick(push, dev, 0);
1028 }
1029
Ben Skeggs78951d22011-11-11 18:13:13 +10001030 nvd0_hdmi_disconnect(encoder);
1031
Ben Skeggs83fc0832011-07-05 13:08:40 +10001032 nv_encoder->crtc = NULL;
1033 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1034 }
1035}
1036
1037static void
1038nvd0_sor_destroy(struct drm_encoder *encoder)
1039{
1040 drm_encoder_cleanup(encoder);
1041 kfree(encoder);
1042}
1043
1044static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = {
1045 .dpms = nvd0_sor_dpms,
1046 .mode_fixup = nvd0_sor_mode_fixup,
1047 .prepare = nvd0_sor_prepare,
1048 .commit = nvd0_sor_commit,
1049 .mode_set = nvd0_sor_mode_set,
1050 .disable = nvd0_sor_disconnect,
1051 .get_crtc = nvd0_display_crtc_get,
1052};
1053
1054static const struct drm_encoder_funcs nvd0_sor_func = {
1055 .destroy = nvd0_sor_destroy,
1056};
1057
1058static int
1059nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe)
1060{
1061 struct drm_device *dev = connector->dev;
1062 struct nouveau_encoder *nv_encoder;
1063 struct drm_encoder *encoder;
1064
1065 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
1066 if (!nv_encoder)
1067 return -ENOMEM;
1068 nv_encoder->dcb = dcbe;
1069 nv_encoder->or = ffs(dcbe->or) - 1;
1070 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1071
1072 encoder = to_drm_encoder(nv_encoder);
1073 encoder->possible_crtcs = dcbe->heads;
1074 encoder->possible_clones = 0;
1075 drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS);
1076 drm_encoder_helper_add(encoder, &nvd0_sor_hfunc);
1077
1078 drm_mode_connector_attach_encoder(connector, encoder);
1079 return 0;
1080}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001081
1082/******************************************************************************
1083 * IRQ
1084 *****************************************************************************/
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001085static struct dcb_entry *
1086lookup_dcb(struct drm_device *dev, int id, u32 mc)
1087{
1088 struct drm_nouveau_private *dev_priv = dev->dev_private;
1089 int type, or, i;
1090
1091 if (id < 4) {
1092 type = OUTPUT_ANALOG;
1093 or = id;
1094 } else {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001095 switch (mc & 0x00000f00) {
1096 case 0x00000000: type = OUTPUT_LVDS; break;
1097 case 0x00000100: type = OUTPUT_TMDS; break;
1098 case 0x00000200: type = OUTPUT_TMDS; break;
1099 case 0x00000500: type = OUTPUT_TMDS; break;
1100 default:
Ben Skeggsee417792011-07-08 14:34:45 +10001101 NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001102 return NULL;
1103 }
1104
1105 or = id - 4;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001106 }
1107
1108 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
1109 struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
1110 if (dcb->type == type && (dcb->or & (1 << or)))
1111 return dcb;
1112 }
1113
Ben Skeggsee417792011-07-08 14:34:45 +10001114 NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001115 return NULL;
1116}
1117
Ben Skeggs46005222011-07-05 11:01:13 +10001118static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001119nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001120{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001121 struct dcb_entry *dcb;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001122 int i;
1123
Ben Skeggsee417792011-07-08 14:34:45 +10001124 for (i = 0; mask && i < 8; i++) {
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001125 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
Ben Skeggsee417792011-07-08 14:34:45 +10001126 if (!(mcc & (1 << crtc)))
1127 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001128
Ben Skeggsee417792011-07-08 14:34:45 +10001129 dcb = lookup_dcb(dev, i, mcc);
1130 if (!dcb)
1131 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001132
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001133 nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001134 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001135
Ben Skeggs270a5742011-07-05 14:16:05 +10001136 nv_wr32(dev, 0x6101d4, 0x00000000);
1137 nv_wr32(dev, 0x6109d4, 0x00000000);
1138 nv_wr32(dev, 0x6101d0, 0x80000000);
1139}
1140
1141static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001142nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001143{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001144 struct dcb_entry *dcb;
Ben Skeggs37b034a2011-07-08 14:43:19 +10001145 u32 or, tmp, pclk;
Ben Skeggsee417792011-07-08 14:34:45 +10001146 int i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001147
Ben Skeggsee417792011-07-08 14:34:45 +10001148 for (i = 0; mask && i < 8; i++) {
1149 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
1150 if (!(mcc & (1 << crtc)))
1151 continue;
1152
1153 dcb = lookup_dcb(dev, i, mcc);
1154 if (!dcb)
1155 continue;
1156
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001157 nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001158 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001159
Ben Skeggsee417792011-07-08 14:34:45 +10001160 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
1161 if (mask & 0x00010000) {
1162 nv50_crtc_set_clock(dev, crtc, pclk);
1163 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001164
Ben Skeggsee417792011-07-08 14:34:45 +10001165 for (i = 0; mask && i < 8; i++) {
1166 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1167 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1168 if (!(mcp & (1 << crtc)))
1169 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001170
Ben Skeggsee417792011-07-08 14:34:45 +10001171 dcb = lookup_dcb(dev, i, mcp);
1172 if (!dcb)
1173 continue;
1174 or = ffs(dcb->or) - 1;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001175
Ben Skeggsee417792011-07-08 14:34:45 +10001176 nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001177
Ben Skeggsee417792011-07-08 14:34:45 +10001178 nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000);
1179 switch (dcb->type) {
1180 case OUTPUT_ANALOG:
1181 nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000);
1182 break;
1183 case OUTPUT_TMDS:
1184 case OUTPUT_LVDS:
1185 if (cfg & 0x00000100)
1186 tmp = 0x00000101;
1187 else
1188 tmp = 0x00000000;
1189
1190 nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
1191 break;
1192 default:
1193 break;
1194 }
1195
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001196 break;
1197 }
1198
Ben Skeggs270a5742011-07-05 14:16:05 +10001199 nv_wr32(dev, 0x6101d4, 0x00000000);
1200 nv_wr32(dev, 0x6109d4, 0x00000000);
1201 nv_wr32(dev, 0x6101d0, 0x80000000);
1202}
1203
1204static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001205nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001206{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001207 struct dcb_entry *dcb;
Ben Skeggsee417792011-07-08 14:34:45 +10001208 int pclk, i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001209
Ben Skeggsee417792011-07-08 14:34:45 +10001210 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001211
Ben Skeggsee417792011-07-08 14:34:45 +10001212 for (i = 0; mask && i < 8; i++) {
1213 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1214 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1215 if (!(mcp & (1 << crtc)))
1216 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001217
Ben Skeggsee417792011-07-08 14:34:45 +10001218 dcb = lookup_dcb(dev, i, mcp);
1219 if (!dcb)
1220 continue;
1221
1222 nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc);
1223 }
1224
Ben Skeggs270a5742011-07-05 14:16:05 +10001225 nv_wr32(dev, 0x6101d4, 0x00000000);
1226 nv_wr32(dev, 0x6109d4, 0x00000000);
1227 nv_wr32(dev, 0x6101d0, 0x80000000);
1228}
1229
1230static void
Ben Skeggsf20ce962011-07-08 13:17:01 +10001231nvd0_display_bh(unsigned long data)
1232{
1233 struct drm_device *dev = (struct drm_device *)data;
1234 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001235 u32 mask, crtc;
1236 int i;
1237
1238 if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
1239 NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset);
1240 NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n",
1241 nv_rd32(dev, 0x6101d0),
1242 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
1243 for (i = 0; i < 8; i++) {
1244 NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n",
1245 i < 4 ? "DAC" : "SOR", i,
1246 nv_rd32(dev, 0x640180 + (i * 0x20)),
1247 nv_rd32(dev, 0x660180 + (i * 0x20)));
1248 }
1249 }
1250
1251 mask = nv_rd32(dev, 0x6101d4);
1252 crtc = 0;
1253 if (!mask) {
1254 mask = nv_rd32(dev, 0x6109d4);
1255 crtc = 1;
1256 }
Ben Skeggsf20ce962011-07-08 13:17:01 +10001257
Ben Skeggsee417792011-07-08 14:34:45 +10001258 if (disp->modeset & 0x00000001)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001259 nvd0_display_unk1_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001260 if (disp->modeset & 0x00000002)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001261 nvd0_display_unk2_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001262 if (disp->modeset & 0x00000004)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001263 nvd0_display_unk4_handler(dev, crtc, mask);
Ben Skeggsf20ce962011-07-08 13:17:01 +10001264}
1265
1266static void
Ben Skeggs46005222011-07-05 11:01:13 +10001267nvd0_display_intr(struct drm_device *dev)
1268{
Ben Skeggsf20ce962011-07-08 13:17:01 +10001269 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001270 u32 intr = nv_rd32(dev, 0x610088);
1271
1272 if (intr & 0x00000002) {
1273 u32 stat = nv_rd32(dev, 0x61009c);
1274 int chid = ffs(stat) - 1;
1275 if (chid >= 0) {
1276 u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12));
1277 u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12));
1278 u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12));
1279
1280 NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x "
1281 "0x%08x 0x%08x\n",
1282 chid, (mthd & 0x0000ffc), data, mthd, unkn);
1283 nv_wr32(dev, 0x61009c, (1 << chid));
1284 nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000);
1285 }
1286
1287 intr &= ~0x00000002;
1288 }
1289
Ben Skeggs270a5742011-07-05 14:16:05 +10001290 if (intr & 0x00100000) {
1291 u32 stat = nv_rd32(dev, 0x6100ac);
1292
1293 if (stat & 0x00000007) {
Ben Skeggsee417792011-07-08 14:34:45 +10001294 disp->modeset = stat;
Ben Skeggsf20ce962011-07-08 13:17:01 +10001295 tasklet_schedule(&disp->tasklet);
Ben Skeggs270a5742011-07-05 14:16:05 +10001296
Ben Skeggsf20ce962011-07-08 13:17:01 +10001297 nv_wr32(dev, 0x6100ac, (stat & 0x00000007));
Ben Skeggs270a5742011-07-05 14:16:05 +10001298 stat &= ~0x00000007;
1299 }
1300
1301 if (stat) {
1302 NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat);
1303 nv_wr32(dev, 0x6100ac, stat);
1304 }
1305
1306 intr &= ~0x00100000;
1307 }
1308
Ben Skeggs46005222011-07-05 11:01:13 +10001309 if (intr & 0x01000000) {
1310 u32 stat = nv_rd32(dev, 0x6100bc);
1311 nv_wr32(dev, 0x6100bc, stat);
1312 intr &= ~0x01000000;
1313 }
1314
1315 if (intr & 0x02000000) {
1316 u32 stat = nv_rd32(dev, 0x6108bc);
1317 nv_wr32(dev, 0x6108bc, stat);
1318 intr &= ~0x02000000;
1319 }
1320
1321 if (intr)
1322 NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr);
1323}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001324
1325/******************************************************************************
1326 * Init
1327 *****************************************************************************/
1328static void
1329nvd0_display_fini(struct drm_device *dev)
1330{
1331 int i;
1332
1333 /* fini cursors */
1334 for (i = 14; i >= 13; i--) {
1335 if (!(nv_rd32(dev, 0x610490 + (i * 0x10)) & 0x00000001))
1336 continue;
1337
1338 nv_mask(dev, 0x610490 + (i * 0x10), 0x00000001, 0x00000000);
1339 nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00000000);
1340 nv_mask(dev, 0x610090, 1 << i, 0x00000000);
1341 nv_mask(dev, 0x6100a0, 1 << i, 0x00000000);
1342 }
1343
1344 /* fini master */
1345 if (nv_rd32(dev, 0x610490) & 0x00000010) {
1346 nv_mask(dev, 0x610490, 0x00000010, 0x00000000);
1347 nv_mask(dev, 0x610490, 0x00000003, 0x00000000);
1348 nv_wait(dev, 0x610490, 0x80000000, 0x00000000);
1349 nv_mask(dev, 0x610090, 0x00000001, 0x00000000);
1350 nv_mask(dev, 0x6100a0, 0x00000001, 0x00000000);
1351 }
1352}
1353
1354int
1355nvd0_display_init(struct drm_device *dev)
1356{
1357 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001358 u32 *push;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001359 int i;
1360
1361 if (nv_rd32(dev, 0x6100ac) & 0x00000100) {
1362 nv_wr32(dev, 0x6100ac, 0x00000100);
1363 nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000);
1364 if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) {
1365 NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n",
1366 nv_rd32(dev, 0x6194e8));
1367 return -EBUSY;
1368 }
1369 }
1370
Ben Skeggsa36f04c2011-07-06 14:39:23 +10001371 /* nfi what these are exactly, i do know that SOR_MODE_CTRL won't
1372 * work at all unless you do the SOR part below.
1373 */
1374 for (i = 0; i < 3; i++) {
1375 u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800));
1376 nv_wr32(dev, 0x6101c0 + (i * 0x800), dac);
1377 }
1378
1379 for (i = 0; i < 4; i++) {
1380 u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800));
1381 nv_wr32(dev, 0x6301c4 + (i * 0x800), sor);
1382 }
1383
1384 for (i = 0; i < 2; i++) {
1385 u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800));
1386 u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800));
1387 u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800));
1388 nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0);
1389 nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1);
1390 nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2);
1391 }
1392
1393 /* point at our hash table / objects, enable interrupts */
Ben Skeggs26f6d882011-07-04 16:25:18 +10001394 nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9);
Ben Skeggs270a5742011-07-05 14:16:05 +10001395 nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001396
1397 /* init master */
Ben Skeggs51beb422011-07-05 10:33:08 +10001398 nv_wr32(dev, 0x610494, (disp->evo[0].handle >> 8) | 3);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001399 nv_wr32(dev, 0x610498, 0x00010000);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001400 nv_wr32(dev, 0x61049c, 0x00000001);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001401 nv_mask(dev, 0x610490, 0x00000010, 0x00000010);
1402 nv_wr32(dev, 0x640000, 0x00000000);
1403 nv_wr32(dev, 0x610490, 0x01000013);
1404 if (!nv_wait(dev, 0x610490, 0x80000000, 0x00000000)) {
1405 NV_ERROR(dev, "PDISP: master 0x%08x\n",
1406 nv_rd32(dev, 0x610490));
1407 return -EBUSY;
1408 }
1409 nv_mask(dev, 0x610090, 0x00000001, 0x00000001);
1410 nv_mask(dev, 0x6100a0, 0x00000001, 0x00000001);
1411
1412 /* init cursors */
1413 for (i = 13; i <= 14; i++) {
1414 nv_wr32(dev, 0x610490 + (i * 0x10), 0x00000001);
1415 if (!nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00010000)) {
1416 NV_ERROR(dev, "PDISP: curs%d 0x%08x\n", i,
1417 nv_rd32(dev, 0x610490 + (i * 0x10)));
1418 return -EBUSY;
1419 }
1420
1421 nv_mask(dev, 0x610090, 1 << i, 1 << i);
1422 nv_mask(dev, 0x6100a0, 1 << i, 1 << i);
1423 }
1424
Ben Skeggsefd272a2011-07-05 11:58:58 +10001425 push = evo_wait(dev, 0, 32);
1426 if (!push)
1427 return -EBUSY;
1428 evo_mthd(push, 0x0088, 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001429 evo_data(push, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001430 evo_mthd(push, 0x0084, 1);
1431 evo_data(push, 0x00000000);
1432 evo_mthd(push, 0x0084, 1);
1433 evo_data(push, 0x80000000);
1434 evo_mthd(push, 0x008c, 1);
1435 evo_data(push, 0x00000000);
1436 evo_kick(push, dev, 0);
1437
Ben Skeggs26f6d882011-07-04 16:25:18 +10001438 return 0;
1439}
1440
1441void
1442nvd0_display_destroy(struct drm_device *dev)
1443{
1444 struct drm_nouveau_private *dev_priv = dev->dev_private;
1445 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs51beb422011-07-05 10:33:08 +10001446 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001447
1448 nvd0_display_fini(dev);
1449
Ben Skeggs51beb422011-07-05 10:33:08 +10001450 pci_free_consistent(pdev, PAGE_SIZE, disp->evo[0].ptr, disp->evo[0].handle);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001451 nouveau_gpuobj_ref(NULL, &disp->mem);
Ben Skeggs46005222011-07-05 11:01:13 +10001452 nouveau_irq_unregister(dev, 26);
Ben Skeggs51beb422011-07-05 10:33:08 +10001453
1454 dev_priv->engine.display.priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001455 kfree(disp);
1456}
1457
1458int
1459nvd0_display_create(struct drm_device *dev)
1460{
1461 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsefd272a2011-07-05 11:58:58 +10001462 struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001463 struct dcb_table *dcb = &dev_priv->vbios.dcb;
1464 struct drm_connector *connector, *tmp;
Ben Skeggs51beb422011-07-05 10:33:08 +10001465 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001466 struct nvd0_display *disp;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001467 struct dcb_entry *dcbe;
1468 int ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001469
1470 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
1471 if (!disp)
1472 return -ENOMEM;
1473 dev_priv->engine.display.priv = disp;
1474
Ben Skeggs438d99e2011-07-05 16:48:06 +10001475 /* create crtc objects to represent the hw heads */
1476 for (i = 0; i < 2; i++) {
1477 ret = nvd0_crtc_create(dev, i);
1478 if (ret)
1479 goto out;
1480 }
1481
Ben Skeggs83fc0832011-07-05 13:08:40 +10001482 /* create encoder/connector objects based on VBIOS DCB table */
1483 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
1484 connector = nouveau_connector_create(dev, dcbe->connector);
1485 if (IS_ERR(connector))
1486 continue;
1487
1488 if (dcbe->location != DCB_LOC_ON_CHIP) {
1489 NV_WARN(dev, "skipping off-chip encoder %d/%d\n",
1490 dcbe->type, ffs(dcbe->or) - 1);
1491 continue;
1492 }
1493
1494 switch (dcbe->type) {
1495 case OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001496 case OUTPUT_LVDS:
Ben Skeggs83fc0832011-07-05 13:08:40 +10001497 nvd0_sor_create(connector, dcbe);
1498 break;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001499 case OUTPUT_ANALOG:
1500 nvd0_dac_create(connector, dcbe);
1501 break;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001502 default:
1503 NV_WARN(dev, "skipping unsupported encoder %d/%d\n",
1504 dcbe->type, ffs(dcbe->or) - 1);
1505 continue;
1506 }
1507 }
1508
1509 /* cull any connectors we created that don't have an encoder */
1510 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
1511 if (connector->encoder_ids[0])
1512 continue;
1513
1514 NV_WARN(dev, "%s has no encoders, removing\n",
1515 drm_get_connector_name(connector));
1516 connector->funcs->destroy(connector);
1517 }
1518
Ben Skeggs46005222011-07-05 11:01:13 +10001519 /* setup interrupt handling */
Ben Skeggsf20ce962011-07-08 13:17:01 +10001520 tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001521 nouveau_irq_register(dev, 26, nvd0_display_intr);
1522
Ben Skeggs51beb422011-07-05 10:33:08 +10001523 /* hash table and dma objects for the memory areas we care about */
Ben Skeggsefd272a2011-07-05 11:58:58 +10001524 ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000,
1525 NVOBJ_FLAG_ZERO_ALLOC, &disp->mem);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001526 if (ret)
1527 goto out;
1528
Ben Skeggsefd272a2011-07-05 11:58:58 +10001529 nv_wo32(disp->mem, 0x1000, 0x00000049);
1530 nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8);
1531 nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8);
1532 nv_wo32(disp->mem, 0x100c, 0x00000000);
1533 nv_wo32(disp->mem, 0x1010, 0x00000000);
1534 nv_wo32(disp->mem, 0x1014, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001535 nv_wo32(disp->mem, 0x0000, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001536 nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001);
1537
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001538 nv_wo32(disp->mem, 0x1020, 0x00000049);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001539 nv_wo32(disp->mem, 0x1024, 0x00000000);
1540 nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8);
1541 nv_wo32(disp->mem, 0x102c, 0x00000000);
1542 nv_wo32(disp->mem, 0x1030, 0x00000000);
1543 nv_wo32(disp->mem, 0x1034, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001544 nv_wo32(disp->mem, 0x0008, NvEvoVRAM);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001545 nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001);
1546
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001547 nv_wo32(disp->mem, 0x1040, 0x00000009);
1548 nv_wo32(disp->mem, 0x1044, 0x00000000);
1549 nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8);
1550 nv_wo32(disp->mem, 0x104c, 0x00000000);
1551 nv_wo32(disp->mem, 0x1050, 0x00000000);
1552 nv_wo32(disp->mem, 0x1054, 0x00000000);
1553 nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP);
1554 nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001);
1555
1556 nv_wo32(disp->mem, 0x1060, 0x0fe00009);
1557 nv_wo32(disp->mem, 0x1064, 0x00000000);
1558 nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8);
1559 nv_wo32(disp->mem, 0x106c, 0x00000000);
1560 nv_wo32(disp->mem, 0x1070, 0x00000000);
1561 nv_wo32(disp->mem, 0x1074, 0x00000000);
1562 nv_wo32(disp->mem, 0x0018, NvEvoFB32);
1563 nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001);
1564
Ben Skeggsefd272a2011-07-05 11:58:58 +10001565 pinstmem->flush(dev);
1566
Ben Skeggs51beb422011-07-05 10:33:08 +10001567 /* push buffers for evo channels */
1568 disp->evo[0].ptr =
1569 pci_alloc_consistent(pdev, PAGE_SIZE, &disp->evo[0].handle);
1570 if (!disp->evo[0].ptr) {
1571 ret = -ENOMEM;
1572 goto out;
1573 }
1574
Ben Skeggs26f6d882011-07-04 16:25:18 +10001575 ret = nvd0_display_init(dev);
1576 if (ret)
1577 goto out;
1578
1579out:
1580 if (ret)
1581 nvd0_display_destroy(dev);
1582 return ret;
1583}