blob: ceb59802d694242ec0401cce73db4543cd5868dc [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{
814 nvd0_audio_mode_set(encoder, mode);
815}
816
817static void
818nvd0_hdmi_disconnect(struct drm_encoder *encoder)
819{
820 nvd0_audio_disconnect(encoder);
821}
822
823/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +1000824 * SOR
825 *****************************************************************************/
Ben Skeggs83fc0832011-07-05 13:08:40 +1000826static void
827nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
828{
829 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
830 struct drm_device *dev = encoder->dev;
831 struct drm_encoder *partner;
832 int or = nv_encoder->or;
833 u32 dpms_ctrl;
834
835 nv_encoder->last_dpms = mode;
836
837 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
838 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
839
840 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
841 continue;
842
843 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +1000844 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +1000845 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
846 return;
847 break;
848 }
849 }
850
851 dpms_ctrl = (mode == DRM_MODE_DPMS_ON);
852 dpms_ctrl |= 0x80000000;
853
854 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
855 nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
856 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
857 nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
858}
859
860static bool
861nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
862 struct drm_display_mode *adjusted_mode)
863{
864 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
865 struct nouveau_connector *nv_connector;
866
867 nv_connector = nouveau_encoder_connector_get(nv_encoder);
868 if (nv_connector && nv_connector->native_mode) {
869 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
870 int id = adjusted_mode->base.id;
871 *adjusted_mode = *nv_connector->native_mode;
872 adjusted_mode->base.id = id;
873 }
874 }
875
876 return true;
877}
878
879static void
880nvd0_sor_prepare(struct drm_encoder *encoder)
881{
882}
883
884static void
885nvd0_sor_commit(struct drm_encoder *encoder)
886{
887}
888
889static void
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000890nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
891 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +1000892{
Ben Skeggs78951d22011-11-11 18:13:13 +1000893 struct drm_device *dev = encoder->dev;
894 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000895 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
896 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000897 struct nouveau_connector *nv_connector;
898 struct nvbios *bios = &dev_priv->vbios;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000899 u32 mode_ctrl = (1 << nv_crtc->index);
Ben Skeggsff8ff502011-07-08 11:53:37 +1000900 u32 *push, or_config;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000901
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000902 nv_connector = nouveau_encoder_connector_get(nv_encoder);
903 switch (nv_encoder->dcb->type) {
904 case OUTPUT_TMDS:
905 if (nv_encoder->dcb->sorconf.link & 1) {
906 if (mode->clock < 165000)
907 mode_ctrl |= 0x00000100;
908 else
909 mode_ctrl |= 0x00000500;
910 } else {
911 mode_ctrl |= 0x00000200;
912 }
Ben Skeggs83fc0832011-07-05 13:08:40 +1000913
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000914 or_config = (mode_ctrl & 0x00000f00) >> 8;
915 if (mode->clock >= 165000)
916 or_config |= 0x0100;
Ben Skeggs78951d22011-11-11 18:13:13 +1000917
918 nvd0_hdmi_mode_set(encoder, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000919 break;
920 case OUTPUT_LVDS:
921 or_config = (mode_ctrl & 0x00000f00) >> 8;
922 if (bios->fp_no_ddc) {
923 if (bios->fp.dual_link)
924 or_config |= 0x0100;
925 if (bios->fp.if_is_24bit)
926 or_config |= 0x0200;
927 } else {
928 if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
929 if (((u8 *)nv_connector->edid)[121] == 2)
930 or_config |= 0x0100;
931 } else
932 if (mode->clock >= bios->fp.duallink_transition_clk) {
933 or_config |= 0x0100;
934 }
935
936 if (or_config & 0x0100) {
937 if (bios->fp.strapless_is_24bit & 2)
938 or_config |= 0x0200;
939 } else {
940 if (bios->fp.strapless_is_24bit & 1)
941 or_config |= 0x0200;
942 }
943
944 if (nv_connector->base.display_info.bpc == 8)
945 or_config |= 0x0200;
946
947 }
948 break;
949 default:
950 BUG_ON(1);
951 break;
952 }
Ben Skeggsff8ff502011-07-08 11:53:37 +1000953
Ben Skeggs83fc0832011-07-05 13:08:40 +1000954 nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
955
Ben Skeggs78951d22011-11-11 18:13:13 +1000956 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +1000957 if (push) {
Ben Skeggsff8ff502011-07-08 11:53:37 +1000958 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2);
Ben Skeggs83fc0832011-07-05 13:08:40 +1000959 evo_data(push, mode_ctrl);
Ben Skeggsff8ff502011-07-08 11:53:37 +1000960 evo_data(push, or_config);
Ben Skeggs78951d22011-11-11 18:13:13 +1000961 evo_kick(push, dev, 0);
Ben Skeggs83fc0832011-07-05 13:08:40 +1000962 }
963
964 nv_encoder->crtc = encoder->crtc;
965}
966
967static void
968nvd0_sor_disconnect(struct drm_encoder *encoder)
969{
970 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
971 struct drm_device *dev = encoder->dev;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000972 u32 *push;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000973
974 if (nv_encoder->crtc) {
Ben Skeggs438d99e2011-07-05 16:48:06 +1000975 nvd0_crtc_prepare(nv_encoder->crtc);
976
977 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +1000978 if (push) {
979 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
980 evo_data(push, 0x00000000);
981 evo_mthd(push, 0x0080, 1);
982 evo_data(push, 0x00000000);
983 evo_kick(push, dev, 0);
984 }
985
Ben Skeggs78951d22011-11-11 18:13:13 +1000986 nvd0_hdmi_disconnect(encoder);
987
Ben Skeggs83fc0832011-07-05 13:08:40 +1000988 nv_encoder->crtc = NULL;
989 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
990 }
991}
992
993static void
994nvd0_sor_destroy(struct drm_encoder *encoder)
995{
996 drm_encoder_cleanup(encoder);
997 kfree(encoder);
998}
999
1000static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = {
1001 .dpms = nvd0_sor_dpms,
1002 .mode_fixup = nvd0_sor_mode_fixup,
1003 .prepare = nvd0_sor_prepare,
1004 .commit = nvd0_sor_commit,
1005 .mode_set = nvd0_sor_mode_set,
1006 .disable = nvd0_sor_disconnect,
1007 .get_crtc = nvd0_display_crtc_get,
1008};
1009
1010static const struct drm_encoder_funcs nvd0_sor_func = {
1011 .destroy = nvd0_sor_destroy,
1012};
1013
1014static int
1015nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe)
1016{
1017 struct drm_device *dev = connector->dev;
1018 struct nouveau_encoder *nv_encoder;
1019 struct drm_encoder *encoder;
1020
1021 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
1022 if (!nv_encoder)
1023 return -ENOMEM;
1024 nv_encoder->dcb = dcbe;
1025 nv_encoder->or = ffs(dcbe->or) - 1;
1026 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1027
1028 encoder = to_drm_encoder(nv_encoder);
1029 encoder->possible_crtcs = dcbe->heads;
1030 encoder->possible_clones = 0;
1031 drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS);
1032 drm_encoder_helper_add(encoder, &nvd0_sor_hfunc);
1033
1034 drm_mode_connector_attach_encoder(connector, encoder);
1035 return 0;
1036}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001037
1038/******************************************************************************
1039 * IRQ
1040 *****************************************************************************/
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001041static struct dcb_entry *
1042lookup_dcb(struct drm_device *dev, int id, u32 mc)
1043{
1044 struct drm_nouveau_private *dev_priv = dev->dev_private;
1045 int type, or, i;
1046
1047 if (id < 4) {
1048 type = OUTPUT_ANALOG;
1049 or = id;
1050 } else {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001051 switch (mc & 0x00000f00) {
1052 case 0x00000000: type = OUTPUT_LVDS; break;
1053 case 0x00000100: type = OUTPUT_TMDS; break;
1054 case 0x00000200: type = OUTPUT_TMDS; break;
1055 case 0x00000500: type = OUTPUT_TMDS; break;
1056 default:
Ben Skeggsee417792011-07-08 14:34:45 +10001057 NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001058 return NULL;
1059 }
1060
1061 or = id - 4;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001062 }
1063
1064 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
1065 struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
1066 if (dcb->type == type && (dcb->or & (1 << or)))
1067 return dcb;
1068 }
1069
Ben Skeggsee417792011-07-08 14:34:45 +10001070 NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001071 return NULL;
1072}
1073
Ben Skeggs46005222011-07-05 11:01:13 +10001074static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001075nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001076{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001077 struct dcb_entry *dcb;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001078 int i;
1079
Ben Skeggsee417792011-07-08 14:34:45 +10001080 for (i = 0; mask && i < 8; i++) {
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001081 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
Ben Skeggsee417792011-07-08 14:34:45 +10001082 if (!(mcc & (1 << crtc)))
1083 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001084
Ben Skeggsee417792011-07-08 14:34:45 +10001085 dcb = lookup_dcb(dev, i, mcc);
1086 if (!dcb)
1087 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001088
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001089 nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001090 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001091
Ben Skeggs270a5742011-07-05 14:16:05 +10001092 nv_wr32(dev, 0x6101d4, 0x00000000);
1093 nv_wr32(dev, 0x6109d4, 0x00000000);
1094 nv_wr32(dev, 0x6101d0, 0x80000000);
1095}
1096
1097static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001098nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001099{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001100 struct dcb_entry *dcb;
Ben Skeggs37b034a2011-07-08 14:43:19 +10001101 u32 or, tmp, pclk;
Ben Skeggsee417792011-07-08 14:34:45 +10001102 int i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001103
Ben Skeggsee417792011-07-08 14:34:45 +10001104 for (i = 0; mask && i < 8; i++) {
1105 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
1106 if (!(mcc & (1 << crtc)))
1107 continue;
1108
1109 dcb = lookup_dcb(dev, i, mcc);
1110 if (!dcb)
1111 continue;
1112
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001113 nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001114 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001115
Ben Skeggsee417792011-07-08 14:34:45 +10001116 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
1117 if (mask & 0x00010000) {
1118 nv50_crtc_set_clock(dev, crtc, pclk);
1119 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001120
Ben Skeggsee417792011-07-08 14:34:45 +10001121 for (i = 0; mask && i < 8; i++) {
1122 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1123 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1124 if (!(mcp & (1 << crtc)))
1125 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001126
Ben Skeggsee417792011-07-08 14:34:45 +10001127 dcb = lookup_dcb(dev, i, mcp);
1128 if (!dcb)
1129 continue;
1130 or = ffs(dcb->or) - 1;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001131
Ben Skeggsee417792011-07-08 14:34:45 +10001132 nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001133
Ben Skeggsee417792011-07-08 14:34:45 +10001134 nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000);
1135 switch (dcb->type) {
1136 case OUTPUT_ANALOG:
1137 nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000);
1138 break;
1139 case OUTPUT_TMDS:
1140 case OUTPUT_LVDS:
1141 if (cfg & 0x00000100)
1142 tmp = 0x00000101;
1143 else
1144 tmp = 0x00000000;
1145
1146 nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
1147 break;
1148 default:
1149 break;
1150 }
1151
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001152 break;
1153 }
1154
Ben Skeggs270a5742011-07-05 14:16:05 +10001155 nv_wr32(dev, 0x6101d4, 0x00000000);
1156 nv_wr32(dev, 0x6109d4, 0x00000000);
1157 nv_wr32(dev, 0x6101d0, 0x80000000);
1158}
1159
1160static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001161nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001162{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001163 struct dcb_entry *dcb;
Ben Skeggsee417792011-07-08 14:34:45 +10001164 int pclk, i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001165
Ben Skeggsee417792011-07-08 14:34:45 +10001166 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001167
Ben Skeggsee417792011-07-08 14:34:45 +10001168 for (i = 0; mask && i < 8; i++) {
1169 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1170 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1171 if (!(mcp & (1 << crtc)))
1172 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001173
Ben Skeggsee417792011-07-08 14:34:45 +10001174 dcb = lookup_dcb(dev, i, mcp);
1175 if (!dcb)
1176 continue;
1177
1178 nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc);
1179 }
1180
Ben Skeggs270a5742011-07-05 14:16:05 +10001181 nv_wr32(dev, 0x6101d4, 0x00000000);
1182 nv_wr32(dev, 0x6109d4, 0x00000000);
1183 nv_wr32(dev, 0x6101d0, 0x80000000);
1184}
1185
1186static void
Ben Skeggsf20ce962011-07-08 13:17:01 +10001187nvd0_display_bh(unsigned long data)
1188{
1189 struct drm_device *dev = (struct drm_device *)data;
1190 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001191 u32 mask, crtc;
1192 int i;
1193
1194 if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
1195 NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset);
1196 NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n",
1197 nv_rd32(dev, 0x6101d0),
1198 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
1199 for (i = 0; i < 8; i++) {
1200 NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n",
1201 i < 4 ? "DAC" : "SOR", i,
1202 nv_rd32(dev, 0x640180 + (i * 0x20)),
1203 nv_rd32(dev, 0x660180 + (i * 0x20)));
1204 }
1205 }
1206
1207 mask = nv_rd32(dev, 0x6101d4);
1208 crtc = 0;
1209 if (!mask) {
1210 mask = nv_rd32(dev, 0x6109d4);
1211 crtc = 1;
1212 }
Ben Skeggsf20ce962011-07-08 13:17:01 +10001213
Ben Skeggsee417792011-07-08 14:34:45 +10001214 if (disp->modeset & 0x00000001)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001215 nvd0_display_unk1_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001216 if (disp->modeset & 0x00000002)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001217 nvd0_display_unk2_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001218 if (disp->modeset & 0x00000004)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001219 nvd0_display_unk4_handler(dev, crtc, mask);
Ben Skeggsf20ce962011-07-08 13:17:01 +10001220}
1221
1222static void
Ben Skeggs46005222011-07-05 11:01:13 +10001223nvd0_display_intr(struct drm_device *dev)
1224{
Ben Skeggsf20ce962011-07-08 13:17:01 +10001225 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001226 u32 intr = nv_rd32(dev, 0x610088);
1227
1228 if (intr & 0x00000002) {
1229 u32 stat = nv_rd32(dev, 0x61009c);
1230 int chid = ffs(stat) - 1;
1231 if (chid >= 0) {
1232 u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12));
1233 u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12));
1234 u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12));
1235
1236 NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x "
1237 "0x%08x 0x%08x\n",
1238 chid, (mthd & 0x0000ffc), data, mthd, unkn);
1239 nv_wr32(dev, 0x61009c, (1 << chid));
1240 nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000);
1241 }
1242
1243 intr &= ~0x00000002;
1244 }
1245
Ben Skeggs270a5742011-07-05 14:16:05 +10001246 if (intr & 0x00100000) {
1247 u32 stat = nv_rd32(dev, 0x6100ac);
1248
1249 if (stat & 0x00000007) {
Ben Skeggsee417792011-07-08 14:34:45 +10001250 disp->modeset = stat;
Ben Skeggsf20ce962011-07-08 13:17:01 +10001251 tasklet_schedule(&disp->tasklet);
Ben Skeggs270a5742011-07-05 14:16:05 +10001252
Ben Skeggsf20ce962011-07-08 13:17:01 +10001253 nv_wr32(dev, 0x6100ac, (stat & 0x00000007));
Ben Skeggs270a5742011-07-05 14:16:05 +10001254 stat &= ~0x00000007;
1255 }
1256
1257 if (stat) {
1258 NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat);
1259 nv_wr32(dev, 0x6100ac, stat);
1260 }
1261
1262 intr &= ~0x00100000;
1263 }
1264
Ben Skeggs46005222011-07-05 11:01:13 +10001265 if (intr & 0x01000000) {
1266 u32 stat = nv_rd32(dev, 0x6100bc);
1267 nv_wr32(dev, 0x6100bc, stat);
1268 intr &= ~0x01000000;
1269 }
1270
1271 if (intr & 0x02000000) {
1272 u32 stat = nv_rd32(dev, 0x6108bc);
1273 nv_wr32(dev, 0x6108bc, stat);
1274 intr &= ~0x02000000;
1275 }
1276
1277 if (intr)
1278 NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr);
1279}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001280
1281/******************************************************************************
1282 * Init
1283 *****************************************************************************/
1284static void
1285nvd0_display_fini(struct drm_device *dev)
1286{
1287 int i;
1288
1289 /* fini cursors */
1290 for (i = 14; i >= 13; i--) {
1291 if (!(nv_rd32(dev, 0x610490 + (i * 0x10)) & 0x00000001))
1292 continue;
1293
1294 nv_mask(dev, 0x610490 + (i * 0x10), 0x00000001, 0x00000000);
1295 nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00000000);
1296 nv_mask(dev, 0x610090, 1 << i, 0x00000000);
1297 nv_mask(dev, 0x6100a0, 1 << i, 0x00000000);
1298 }
1299
1300 /* fini master */
1301 if (nv_rd32(dev, 0x610490) & 0x00000010) {
1302 nv_mask(dev, 0x610490, 0x00000010, 0x00000000);
1303 nv_mask(dev, 0x610490, 0x00000003, 0x00000000);
1304 nv_wait(dev, 0x610490, 0x80000000, 0x00000000);
1305 nv_mask(dev, 0x610090, 0x00000001, 0x00000000);
1306 nv_mask(dev, 0x6100a0, 0x00000001, 0x00000000);
1307 }
1308}
1309
1310int
1311nvd0_display_init(struct drm_device *dev)
1312{
1313 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001314 u32 *push;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001315 int i;
1316
1317 if (nv_rd32(dev, 0x6100ac) & 0x00000100) {
1318 nv_wr32(dev, 0x6100ac, 0x00000100);
1319 nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000);
1320 if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) {
1321 NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n",
1322 nv_rd32(dev, 0x6194e8));
1323 return -EBUSY;
1324 }
1325 }
1326
Ben Skeggsa36f04c2011-07-06 14:39:23 +10001327 /* nfi what these are exactly, i do know that SOR_MODE_CTRL won't
1328 * work at all unless you do the SOR part below.
1329 */
1330 for (i = 0; i < 3; i++) {
1331 u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800));
1332 nv_wr32(dev, 0x6101c0 + (i * 0x800), dac);
1333 }
1334
1335 for (i = 0; i < 4; i++) {
1336 u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800));
1337 nv_wr32(dev, 0x6301c4 + (i * 0x800), sor);
1338 }
1339
1340 for (i = 0; i < 2; i++) {
1341 u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800));
1342 u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800));
1343 u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800));
1344 nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0);
1345 nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1);
1346 nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2);
1347 }
1348
1349 /* point at our hash table / objects, enable interrupts */
Ben Skeggs26f6d882011-07-04 16:25:18 +10001350 nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9);
Ben Skeggs270a5742011-07-05 14:16:05 +10001351 nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001352
1353 /* init master */
Ben Skeggs51beb422011-07-05 10:33:08 +10001354 nv_wr32(dev, 0x610494, (disp->evo[0].handle >> 8) | 3);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001355 nv_wr32(dev, 0x610498, 0x00010000);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001356 nv_wr32(dev, 0x61049c, 0x00000001);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001357 nv_mask(dev, 0x610490, 0x00000010, 0x00000010);
1358 nv_wr32(dev, 0x640000, 0x00000000);
1359 nv_wr32(dev, 0x610490, 0x01000013);
1360 if (!nv_wait(dev, 0x610490, 0x80000000, 0x00000000)) {
1361 NV_ERROR(dev, "PDISP: master 0x%08x\n",
1362 nv_rd32(dev, 0x610490));
1363 return -EBUSY;
1364 }
1365 nv_mask(dev, 0x610090, 0x00000001, 0x00000001);
1366 nv_mask(dev, 0x6100a0, 0x00000001, 0x00000001);
1367
1368 /* init cursors */
1369 for (i = 13; i <= 14; i++) {
1370 nv_wr32(dev, 0x610490 + (i * 0x10), 0x00000001);
1371 if (!nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00010000)) {
1372 NV_ERROR(dev, "PDISP: curs%d 0x%08x\n", i,
1373 nv_rd32(dev, 0x610490 + (i * 0x10)));
1374 return -EBUSY;
1375 }
1376
1377 nv_mask(dev, 0x610090, 1 << i, 1 << i);
1378 nv_mask(dev, 0x6100a0, 1 << i, 1 << i);
1379 }
1380
Ben Skeggsefd272a2011-07-05 11:58:58 +10001381 push = evo_wait(dev, 0, 32);
1382 if (!push)
1383 return -EBUSY;
1384 evo_mthd(push, 0x0088, 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001385 evo_data(push, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001386 evo_mthd(push, 0x0084, 1);
1387 evo_data(push, 0x00000000);
1388 evo_mthd(push, 0x0084, 1);
1389 evo_data(push, 0x80000000);
1390 evo_mthd(push, 0x008c, 1);
1391 evo_data(push, 0x00000000);
1392 evo_kick(push, dev, 0);
1393
Ben Skeggs26f6d882011-07-04 16:25:18 +10001394 return 0;
1395}
1396
1397void
1398nvd0_display_destroy(struct drm_device *dev)
1399{
1400 struct drm_nouveau_private *dev_priv = dev->dev_private;
1401 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs51beb422011-07-05 10:33:08 +10001402 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001403
1404 nvd0_display_fini(dev);
1405
Ben Skeggs51beb422011-07-05 10:33:08 +10001406 pci_free_consistent(pdev, PAGE_SIZE, disp->evo[0].ptr, disp->evo[0].handle);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001407 nouveau_gpuobj_ref(NULL, &disp->mem);
Ben Skeggs46005222011-07-05 11:01:13 +10001408 nouveau_irq_unregister(dev, 26);
Ben Skeggs51beb422011-07-05 10:33:08 +10001409
1410 dev_priv->engine.display.priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001411 kfree(disp);
1412}
1413
1414int
1415nvd0_display_create(struct drm_device *dev)
1416{
1417 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsefd272a2011-07-05 11:58:58 +10001418 struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001419 struct dcb_table *dcb = &dev_priv->vbios.dcb;
1420 struct drm_connector *connector, *tmp;
Ben Skeggs51beb422011-07-05 10:33:08 +10001421 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001422 struct nvd0_display *disp;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001423 struct dcb_entry *dcbe;
1424 int ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001425
1426 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
1427 if (!disp)
1428 return -ENOMEM;
1429 dev_priv->engine.display.priv = disp;
1430
Ben Skeggs438d99e2011-07-05 16:48:06 +10001431 /* create crtc objects to represent the hw heads */
1432 for (i = 0; i < 2; i++) {
1433 ret = nvd0_crtc_create(dev, i);
1434 if (ret)
1435 goto out;
1436 }
1437
Ben Skeggs83fc0832011-07-05 13:08:40 +10001438 /* create encoder/connector objects based on VBIOS DCB table */
1439 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
1440 connector = nouveau_connector_create(dev, dcbe->connector);
1441 if (IS_ERR(connector))
1442 continue;
1443
1444 if (dcbe->location != DCB_LOC_ON_CHIP) {
1445 NV_WARN(dev, "skipping off-chip encoder %d/%d\n",
1446 dcbe->type, ffs(dcbe->or) - 1);
1447 continue;
1448 }
1449
1450 switch (dcbe->type) {
1451 case OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001452 case OUTPUT_LVDS:
Ben Skeggs83fc0832011-07-05 13:08:40 +10001453 nvd0_sor_create(connector, dcbe);
1454 break;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001455 case OUTPUT_ANALOG:
1456 nvd0_dac_create(connector, dcbe);
1457 break;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001458 default:
1459 NV_WARN(dev, "skipping unsupported encoder %d/%d\n",
1460 dcbe->type, ffs(dcbe->or) - 1);
1461 continue;
1462 }
1463 }
1464
1465 /* cull any connectors we created that don't have an encoder */
1466 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
1467 if (connector->encoder_ids[0])
1468 continue;
1469
1470 NV_WARN(dev, "%s has no encoders, removing\n",
1471 drm_get_connector_name(connector));
1472 connector->funcs->destroy(connector);
1473 }
1474
Ben Skeggs46005222011-07-05 11:01:13 +10001475 /* setup interrupt handling */
Ben Skeggsf20ce962011-07-08 13:17:01 +10001476 tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001477 nouveau_irq_register(dev, 26, nvd0_display_intr);
1478
Ben Skeggs51beb422011-07-05 10:33:08 +10001479 /* hash table and dma objects for the memory areas we care about */
Ben Skeggsefd272a2011-07-05 11:58:58 +10001480 ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000,
1481 NVOBJ_FLAG_ZERO_ALLOC, &disp->mem);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001482 if (ret)
1483 goto out;
1484
Ben Skeggsefd272a2011-07-05 11:58:58 +10001485 nv_wo32(disp->mem, 0x1000, 0x00000049);
1486 nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8);
1487 nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8);
1488 nv_wo32(disp->mem, 0x100c, 0x00000000);
1489 nv_wo32(disp->mem, 0x1010, 0x00000000);
1490 nv_wo32(disp->mem, 0x1014, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001491 nv_wo32(disp->mem, 0x0000, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001492 nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001);
1493
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001494 nv_wo32(disp->mem, 0x1020, 0x00000049);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001495 nv_wo32(disp->mem, 0x1024, 0x00000000);
1496 nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8);
1497 nv_wo32(disp->mem, 0x102c, 0x00000000);
1498 nv_wo32(disp->mem, 0x1030, 0x00000000);
1499 nv_wo32(disp->mem, 0x1034, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001500 nv_wo32(disp->mem, 0x0008, NvEvoVRAM);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001501 nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001);
1502
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001503 nv_wo32(disp->mem, 0x1040, 0x00000009);
1504 nv_wo32(disp->mem, 0x1044, 0x00000000);
1505 nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8);
1506 nv_wo32(disp->mem, 0x104c, 0x00000000);
1507 nv_wo32(disp->mem, 0x1050, 0x00000000);
1508 nv_wo32(disp->mem, 0x1054, 0x00000000);
1509 nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP);
1510 nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001);
1511
1512 nv_wo32(disp->mem, 0x1060, 0x0fe00009);
1513 nv_wo32(disp->mem, 0x1064, 0x00000000);
1514 nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8);
1515 nv_wo32(disp->mem, 0x106c, 0x00000000);
1516 nv_wo32(disp->mem, 0x1070, 0x00000000);
1517 nv_wo32(disp->mem, 0x1074, 0x00000000);
1518 nv_wo32(disp->mem, 0x0018, NvEvoFB32);
1519 nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001);
1520
Ben Skeggsefd272a2011-07-05 11:58:58 +10001521 pinstmem->flush(dev);
1522
Ben Skeggs51beb422011-07-05 10:33:08 +10001523 /* push buffers for evo channels */
1524 disp->evo[0].ptr =
1525 pci_alloc_consistent(pdev, PAGE_SIZE, &disp->evo[0].handle);
1526 if (!disp->evo[0].ptr) {
1527 ret = -ENOMEM;
1528 goto out;
1529 }
1530
Ben Skeggs26f6d882011-07-04 16:25:18 +10001531 ret = nvd0_display_init(dev);
1532 if (ret)
1533 goto out;
1534
1535out:
1536 if (ret)
1537 nvd0_display_destroy(dev);
1538 return ret;
1539}