blob: e9da42c733717531b5e2f581d073a00021924b7e [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/******************************************************************************
769 * SOR
770 *****************************************************************************/
Ben Skeggs83fc0832011-07-05 13:08:40 +1000771static void
772nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
773{
774 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
775 struct drm_device *dev = encoder->dev;
776 struct drm_encoder *partner;
777 int or = nv_encoder->or;
778 u32 dpms_ctrl;
779
780 nv_encoder->last_dpms = mode;
781
782 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
783 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
784
785 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
786 continue;
787
788 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +1000789 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +1000790 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
791 return;
792 break;
793 }
794 }
795
796 dpms_ctrl = (mode == DRM_MODE_DPMS_ON);
797 dpms_ctrl |= 0x80000000;
798
799 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
800 nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
801 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
802 nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
803}
804
805static bool
806nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
807 struct drm_display_mode *adjusted_mode)
808{
809 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
810 struct nouveau_connector *nv_connector;
811
812 nv_connector = nouveau_encoder_connector_get(nv_encoder);
813 if (nv_connector && nv_connector->native_mode) {
814 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
815 int id = adjusted_mode->base.id;
816 *adjusted_mode = *nv_connector->native_mode;
817 adjusted_mode->base.id = id;
818 }
819 }
820
821 return true;
822}
823
824static void
825nvd0_sor_prepare(struct drm_encoder *encoder)
826{
827}
828
829static void
830nvd0_sor_commit(struct drm_encoder *encoder)
831{
832}
833
834static void
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000835nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
836 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +1000837{
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000838 struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000839 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
840 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000841 struct nouveau_connector *nv_connector;
842 struct nvbios *bios = &dev_priv->vbios;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000843 u32 mode_ctrl = (1 << nv_crtc->index);
Ben Skeggsff8ff502011-07-08 11:53:37 +1000844 u32 *push, or_config;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000845
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000846 nv_connector = nouveau_encoder_connector_get(nv_encoder);
847 switch (nv_encoder->dcb->type) {
848 case OUTPUT_TMDS:
849 if (nv_encoder->dcb->sorconf.link & 1) {
850 if (mode->clock < 165000)
851 mode_ctrl |= 0x00000100;
852 else
853 mode_ctrl |= 0x00000500;
854 } else {
855 mode_ctrl |= 0x00000200;
856 }
Ben Skeggs83fc0832011-07-05 13:08:40 +1000857
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000858 or_config = (mode_ctrl & 0x00000f00) >> 8;
859 if (mode->clock >= 165000)
860 or_config |= 0x0100;
861 break;
862 case OUTPUT_LVDS:
863 or_config = (mode_ctrl & 0x00000f00) >> 8;
864 if (bios->fp_no_ddc) {
865 if (bios->fp.dual_link)
866 or_config |= 0x0100;
867 if (bios->fp.if_is_24bit)
868 or_config |= 0x0200;
869 } else {
870 if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
871 if (((u8 *)nv_connector->edid)[121] == 2)
872 or_config |= 0x0100;
873 } else
874 if (mode->clock >= bios->fp.duallink_transition_clk) {
875 or_config |= 0x0100;
876 }
877
878 if (or_config & 0x0100) {
879 if (bios->fp.strapless_is_24bit & 2)
880 or_config |= 0x0200;
881 } else {
882 if (bios->fp.strapless_is_24bit & 1)
883 or_config |= 0x0200;
884 }
885
886 if (nv_connector->base.display_info.bpc == 8)
887 or_config |= 0x0200;
888
889 }
890 break;
891 default:
892 BUG_ON(1);
893 break;
894 }
Ben Skeggsff8ff502011-07-08 11:53:37 +1000895
Ben Skeggs83fc0832011-07-05 13:08:40 +1000896 nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
897
Ben Skeggsff8ff502011-07-08 11:53:37 +1000898 push = evo_wait(encoder->dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +1000899 if (push) {
Ben Skeggsff8ff502011-07-08 11:53:37 +1000900 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2);
Ben Skeggs83fc0832011-07-05 13:08:40 +1000901 evo_data(push, mode_ctrl);
Ben Skeggsff8ff502011-07-08 11:53:37 +1000902 evo_data(push, or_config);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000903 evo_kick(push, encoder->dev, 0);
Ben Skeggs83fc0832011-07-05 13:08:40 +1000904 }
905
906 nv_encoder->crtc = encoder->crtc;
907}
908
909static void
910nvd0_sor_disconnect(struct drm_encoder *encoder)
911{
912 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
913 struct drm_device *dev = encoder->dev;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000914 u32 *push;
Ben Skeggs83fc0832011-07-05 13:08:40 +1000915
916 if (nv_encoder->crtc) {
Ben Skeggs438d99e2011-07-05 16:48:06 +1000917 nvd0_crtc_prepare(nv_encoder->crtc);
918
919 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +1000920 if (push) {
921 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
922 evo_data(push, 0x00000000);
923 evo_mthd(push, 0x0080, 1);
924 evo_data(push, 0x00000000);
925 evo_kick(push, dev, 0);
926 }
927
928 nv_encoder->crtc = NULL;
929 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
930 }
931}
932
933static void
934nvd0_sor_destroy(struct drm_encoder *encoder)
935{
936 drm_encoder_cleanup(encoder);
937 kfree(encoder);
938}
939
940static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = {
941 .dpms = nvd0_sor_dpms,
942 .mode_fixup = nvd0_sor_mode_fixup,
943 .prepare = nvd0_sor_prepare,
944 .commit = nvd0_sor_commit,
945 .mode_set = nvd0_sor_mode_set,
946 .disable = nvd0_sor_disconnect,
947 .get_crtc = nvd0_display_crtc_get,
948};
949
950static const struct drm_encoder_funcs nvd0_sor_func = {
951 .destroy = nvd0_sor_destroy,
952};
953
954static int
955nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe)
956{
957 struct drm_device *dev = connector->dev;
958 struct nouveau_encoder *nv_encoder;
959 struct drm_encoder *encoder;
960
961 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
962 if (!nv_encoder)
963 return -ENOMEM;
964 nv_encoder->dcb = dcbe;
965 nv_encoder->or = ffs(dcbe->or) - 1;
966 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
967
968 encoder = to_drm_encoder(nv_encoder);
969 encoder->possible_crtcs = dcbe->heads;
970 encoder->possible_clones = 0;
971 drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS);
972 drm_encoder_helper_add(encoder, &nvd0_sor_hfunc);
973
974 drm_mode_connector_attach_encoder(connector, encoder);
975 return 0;
976}
Ben Skeggs26f6d882011-07-04 16:25:18 +1000977
978/******************************************************************************
979 * IRQ
980 *****************************************************************************/
Ben Skeggs3a89cd02011-07-07 10:47:10 +1000981static struct dcb_entry *
982lookup_dcb(struct drm_device *dev, int id, u32 mc)
983{
984 struct drm_nouveau_private *dev_priv = dev->dev_private;
985 int type, or, i;
986
987 if (id < 4) {
988 type = OUTPUT_ANALOG;
989 or = id;
990 } else {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000991 switch (mc & 0x00000f00) {
992 case 0x00000000: type = OUTPUT_LVDS; break;
993 case 0x00000100: type = OUTPUT_TMDS; break;
994 case 0x00000200: type = OUTPUT_TMDS; break;
995 case 0x00000500: type = OUTPUT_TMDS; break;
996 default:
Ben Skeggsee417792011-07-08 14:34:45 +1000997 NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +1000998 return NULL;
999 }
1000
1001 or = id - 4;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001002 }
1003
1004 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
1005 struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
1006 if (dcb->type == type && (dcb->or & (1 << or)))
1007 return dcb;
1008 }
1009
Ben Skeggsee417792011-07-08 14:34:45 +10001010 NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001011 return NULL;
1012}
1013
Ben Skeggs46005222011-07-05 11:01:13 +10001014static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001015nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001016{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001017 struct dcb_entry *dcb;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001018 int i;
1019
Ben Skeggsee417792011-07-08 14:34:45 +10001020 for (i = 0; mask && i < 8; i++) {
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001021 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
Ben Skeggsee417792011-07-08 14:34:45 +10001022 if (!(mcc & (1 << crtc)))
1023 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001024
Ben Skeggsee417792011-07-08 14:34:45 +10001025 dcb = lookup_dcb(dev, i, mcc);
1026 if (!dcb)
1027 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001028
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001029 nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001030 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001031
Ben Skeggs270a5742011-07-05 14:16:05 +10001032 nv_wr32(dev, 0x6101d4, 0x00000000);
1033 nv_wr32(dev, 0x6109d4, 0x00000000);
1034 nv_wr32(dev, 0x6101d0, 0x80000000);
1035}
1036
1037static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001038nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001039{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001040 struct dcb_entry *dcb;
Ben Skeggs37b034a2011-07-08 14:43:19 +10001041 u32 or, tmp, pclk;
Ben Skeggsee417792011-07-08 14:34:45 +10001042 int i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001043
Ben Skeggsee417792011-07-08 14:34:45 +10001044 for (i = 0; mask && i < 8; i++) {
1045 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
1046 if (!(mcc & (1 << crtc)))
1047 continue;
1048
1049 dcb = lookup_dcb(dev, i, mcc);
1050 if (!dcb)
1051 continue;
1052
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001053 nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001054 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001055
Ben Skeggsee417792011-07-08 14:34:45 +10001056 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
1057 if (mask & 0x00010000) {
1058 nv50_crtc_set_clock(dev, crtc, pclk);
1059 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001060
Ben Skeggsee417792011-07-08 14:34:45 +10001061 for (i = 0; mask && i < 8; i++) {
1062 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1063 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1064 if (!(mcp & (1 << crtc)))
1065 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001066
Ben Skeggsee417792011-07-08 14:34:45 +10001067 dcb = lookup_dcb(dev, i, mcp);
1068 if (!dcb)
1069 continue;
1070 or = ffs(dcb->or) - 1;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001071
Ben Skeggsee417792011-07-08 14:34:45 +10001072 nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001073
Ben Skeggsee417792011-07-08 14:34:45 +10001074 nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000);
1075 switch (dcb->type) {
1076 case OUTPUT_ANALOG:
1077 nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000);
1078 break;
1079 case OUTPUT_TMDS:
1080 case OUTPUT_LVDS:
1081 if (cfg & 0x00000100)
1082 tmp = 0x00000101;
1083 else
1084 tmp = 0x00000000;
1085
1086 nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
1087 break;
1088 default:
1089 break;
1090 }
1091
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001092 break;
1093 }
1094
Ben Skeggs270a5742011-07-05 14:16:05 +10001095 nv_wr32(dev, 0x6101d4, 0x00000000);
1096 nv_wr32(dev, 0x6109d4, 0x00000000);
1097 nv_wr32(dev, 0x6101d0, 0x80000000);
1098}
1099
1100static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001101nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001102{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001103 struct dcb_entry *dcb;
Ben Skeggsee417792011-07-08 14:34:45 +10001104 int pclk, i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001105
Ben Skeggsee417792011-07-08 14:34:45 +10001106 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001107
Ben Skeggsee417792011-07-08 14:34:45 +10001108 for (i = 0; mask && i < 8; i++) {
1109 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1110 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1111 if (!(mcp & (1 << crtc)))
1112 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001113
Ben Skeggsee417792011-07-08 14:34:45 +10001114 dcb = lookup_dcb(dev, i, mcp);
1115 if (!dcb)
1116 continue;
1117
1118 nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc);
1119 }
1120
Ben Skeggs270a5742011-07-05 14:16:05 +10001121 nv_wr32(dev, 0x6101d4, 0x00000000);
1122 nv_wr32(dev, 0x6109d4, 0x00000000);
1123 nv_wr32(dev, 0x6101d0, 0x80000000);
1124}
1125
1126static void
Ben Skeggsf20ce962011-07-08 13:17:01 +10001127nvd0_display_bh(unsigned long data)
1128{
1129 struct drm_device *dev = (struct drm_device *)data;
1130 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001131 u32 mask, crtc;
1132 int i;
1133
1134 if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
1135 NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset);
1136 NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n",
1137 nv_rd32(dev, 0x6101d0),
1138 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
1139 for (i = 0; i < 8; i++) {
1140 NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n",
1141 i < 4 ? "DAC" : "SOR", i,
1142 nv_rd32(dev, 0x640180 + (i * 0x20)),
1143 nv_rd32(dev, 0x660180 + (i * 0x20)));
1144 }
1145 }
1146
1147 mask = nv_rd32(dev, 0x6101d4);
1148 crtc = 0;
1149 if (!mask) {
1150 mask = nv_rd32(dev, 0x6109d4);
1151 crtc = 1;
1152 }
Ben Skeggsf20ce962011-07-08 13:17:01 +10001153
Ben Skeggsee417792011-07-08 14:34:45 +10001154 if (disp->modeset & 0x00000001)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001155 nvd0_display_unk1_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001156 if (disp->modeset & 0x00000002)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001157 nvd0_display_unk2_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001158 if (disp->modeset & 0x00000004)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001159 nvd0_display_unk4_handler(dev, crtc, mask);
Ben Skeggsf20ce962011-07-08 13:17:01 +10001160}
1161
1162static void
Ben Skeggs46005222011-07-05 11:01:13 +10001163nvd0_display_intr(struct drm_device *dev)
1164{
Ben Skeggsf20ce962011-07-08 13:17:01 +10001165 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001166 u32 intr = nv_rd32(dev, 0x610088);
1167
1168 if (intr & 0x00000002) {
1169 u32 stat = nv_rd32(dev, 0x61009c);
1170 int chid = ffs(stat) - 1;
1171 if (chid >= 0) {
1172 u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12));
1173 u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12));
1174 u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12));
1175
1176 NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x "
1177 "0x%08x 0x%08x\n",
1178 chid, (mthd & 0x0000ffc), data, mthd, unkn);
1179 nv_wr32(dev, 0x61009c, (1 << chid));
1180 nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000);
1181 }
1182
1183 intr &= ~0x00000002;
1184 }
1185
Ben Skeggs270a5742011-07-05 14:16:05 +10001186 if (intr & 0x00100000) {
1187 u32 stat = nv_rd32(dev, 0x6100ac);
1188
1189 if (stat & 0x00000007) {
Ben Skeggsee417792011-07-08 14:34:45 +10001190 disp->modeset = stat;
Ben Skeggsf20ce962011-07-08 13:17:01 +10001191 tasklet_schedule(&disp->tasklet);
Ben Skeggs270a5742011-07-05 14:16:05 +10001192
Ben Skeggsf20ce962011-07-08 13:17:01 +10001193 nv_wr32(dev, 0x6100ac, (stat & 0x00000007));
Ben Skeggs270a5742011-07-05 14:16:05 +10001194 stat &= ~0x00000007;
1195 }
1196
1197 if (stat) {
1198 NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat);
1199 nv_wr32(dev, 0x6100ac, stat);
1200 }
1201
1202 intr &= ~0x00100000;
1203 }
1204
Ben Skeggs46005222011-07-05 11:01:13 +10001205 if (intr & 0x01000000) {
1206 u32 stat = nv_rd32(dev, 0x6100bc);
1207 nv_wr32(dev, 0x6100bc, stat);
1208 intr &= ~0x01000000;
1209 }
1210
1211 if (intr & 0x02000000) {
1212 u32 stat = nv_rd32(dev, 0x6108bc);
1213 nv_wr32(dev, 0x6108bc, stat);
1214 intr &= ~0x02000000;
1215 }
1216
1217 if (intr)
1218 NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr);
1219}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001220
1221/******************************************************************************
1222 * Init
1223 *****************************************************************************/
1224static void
1225nvd0_display_fini(struct drm_device *dev)
1226{
1227 int i;
1228
1229 /* fini cursors */
1230 for (i = 14; i >= 13; i--) {
1231 if (!(nv_rd32(dev, 0x610490 + (i * 0x10)) & 0x00000001))
1232 continue;
1233
1234 nv_mask(dev, 0x610490 + (i * 0x10), 0x00000001, 0x00000000);
1235 nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00000000);
1236 nv_mask(dev, 0x610090, 1 << i, 0x00000000);
1237 nv_mask(dev, 0x6100a0, 1 << i, 0x00000000);
1238 }
1239
1240 /* fini master */
1241 if (nv_rd32(dev, 0x610490) & 0x00000010) {
1242 nv_mask(dev, 0x610490, 0x00000010, 0x00000000);
1243 nv_mask(dev, 0x610490, 0x00000003, 0x00000000);
1244 nv_wait(dev, 0x610490, 0x80000000, 0x00000000);
1245 nv_mask(dev, 0x610090, 0x00000001, 0x00000000);
1246 nv_mask(dev, 0x6100a0, 0x00000001, 0x00000000);
1247 }
1248}
1249
1250int
1251nvd0_display_init(struct drm_device *dev)
1252{
1253 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001254 u32 *push;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001255 int i;
1256
1257 if (nv_rd32(dev, 0x6100ac) & 0x00000100) {
1258 nv_wr32(dev, 0x6100ac, 0x00000100);
1259 nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000);
1260 if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) {
1261 NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n",
1262 nv_rd32(dev, 0x6194e8));
1263 return -EBUSY;
1264 }
1265 }
1266
Ben Skeggsa36f04c2011-07-06 14:39:23 +10001267 /* nfi what these are exactly, i do know that SOR_MODE_CTRL won't
1268 * work at all unless you do the SOR part below.
1269 */
1270 for (i = 0; i < 3; i++) {
1271 u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800));
1272 nv_wr32(dev, 0x6101c0 + (i * 0x800), dac);
1273 }
1274
1275 for (i = 0; i < 4; i++) {
1276 u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800));
1277 nv_wr32(dev, 0x6301c4 + (i * 0x800), sor);
1278 }
1279
1280 for (i = 0; i < 2; i++) {
1281 u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800));
1282 u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800));
1283 u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800));
1284 nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0);
1285 nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1);
1286 nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2);
1287 }
1288
1289 /* point at our hash table / objects, enable interrupts */
Ben Skeggs26f6d882011-07-04 16:25:18 +10001290 nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9);
Ben Skeggs270a5742011-07-05 14:16:05 +10001291 nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001292
1293 /* init master */
Ben Skeggs51beb422011-07-05 10:33:08 +10001294 nv_wr32(dev, 0x610494, (disp->evo[0].handle >> 8) | 3);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001295 nv_wr32(dev, 0x610498, 0x00010000);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001296 nv_wr32(dev, 0x61049c, 0x00000001);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001297 nv_mask(dev, 0x610490, 0x00000010, 0x00000010);
1298 nv_wr32(dev, 0x640000, 0x00000000);
1299 nv_wr32(dev, 0x610490, 0x01000013);
1300 if (!nv_wait(dev, 0x610490, 0x80000000, 0x00000000)) {
1301 NV_ERROR(dev, "PDISP: master 0x%08x\n",
1302 nv_rd32(dev, 0x610490));
1303 return -EBUSY;
1304 }
1305 nv_mask(dev, 0x610090, 0x00000001, 0x00000001);
1306 nv_mask(dev, 0x6100a0, 0x00000001, 0x00000001);
1307
1308 /* init cursors */
1309 for (i = 13; i <= 14; i++) {
1310 nv_wr32(dev, 0x610490 + (i * 0x10), 0x00000001);
1311 if (!nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00010000)) {
1312 NV_ERROR(dev, "PDISP: curs%d 0x%08x\n", i,
1313 nv_rd32(dev, 0x610490 + (i * 0x10)));
1314 return -EBUSY;
1315 }
1316
1317 nv_mask(dev, 0x610090, 1 << i, 1 << i);
1318 nv_mask(dev, 0x6100a0, 1 << i, 1 << i);
1319 }
1320
Ben Skeggsefd272a2011-07-05 11:58:58 +10001321 push = evo_wait(dev, 0, 32);
1322 if (!push)
1323 return -EBUSY;
1324 evo_mthd(push, 0x0088, 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001325 evo_data(push, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001326 evo_mthd(push, 0x0084, 1);
1327 evo_data(push, 0x00000000);
1328 evo_mthd(push, 0x0084, 1);
1329 evo_data(push, 0x80000000);
1330 evo_mthd(push, 0x008c, 1);
1331 evo_data(push, 0x00000000);
1332 evo_kick(push, dev, 0);
1333
Ben Skeggs26f6d882011-07-04 16:25:18 +10001334 return 0;
1335}
1336
1337void
1338nvd0_display_destroy(struct drm_device *dev)
1339{
1340 struct drm_nouveau_private *dev_priv = dev->dev_private;
1341 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs51beb422011-07-05 10:33:08 +10001342 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001343
1344 nvd0_display_fini(dev);
1345
Ben Skeggs51beb422011-07-05 10:33:08 +10001346 pci_free_consistent(pdev, PAGE_SIZE, disp->evo[0].ptr, disp->evo[0].handle);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001347 nouveau_gpuobj_ref(NULL, &disp->mem);
Ben Skeggs46005222011-07-05 11:01:13 +10001348 nouveau_irq_unregister(dev, 26);
Ben Skeggs51beb422011-07-05 10:33:08 +10001349
1350 dev_priv->engine.display.priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001351 kfree(disp);
1352}
1353
1354int
1355nvd0_display_create(struct drm_device *dev)
1356{
1357 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsefd272a2011-07-05 11:58:58 +10001358 struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001359 struct dcb_table *dcb = &dev_priv->vbios.dcb;
1360 struct drm_connector *connector, *tmp;
Ben Skeggs51beb422011-07-05 10:33:08 +10001361 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001362 struct nvd0_display *disp;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001363 struct dcb_entry *dcbe;
1364 int ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001365
1366 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
1367 if (!disp)
1368 return -ENOMEM;
1369 dev_priv->engine.display.priv = disp;
1370
Ben Skeggs438d99e2011-07-05 16:48:06 +10001371 /* create crtc objects to represent the hw heads */
1372 for (i = 0; i < 2; i++) {
1373 ret = nvd0_crtc_create(dev, i);
1374 if (ret)
1375 goto out;
1376 }
1377
Ben Skeggs83fc0832011-07-05 13:08:40 +10001378 /* create encoder/connector objects based on VBIOS DCB table */
1379 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
1380 connector = nouveau_connector_create(dev, dcbe->connector);
1381 if (IS_ERR(connector))
1382 continue;
1383
1384 if (dcbe->location != DCB_LOC_ON_CHIP) {
1385 NV_WARN(dev, "skipping off-chip encoder %d/%d\n",
1386 dcbe->type, ffs(dcbe->or) - 1);
1387 continue;
1388 }
1389
1390 switch (dcbe->type) {
1391 case OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001392 case OUTPUT_LVDS:
Ben Skeggs83fc0832011-07-05 13:08:40 +10001393 nvd0_sor_create(connector, dcbe);
1394 break;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001395 case OUTPUT_ANALOG:
1396 nvd0_dac_create(connector, dcbe);
1397 break;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001398 default:
1399 NV_WARN(dev, "skipping unsupported encoder %d/%d\n",
1400 dcbe->type, ffs(dcbe->or) - 1);
1401 continue;
1402 }
1403 }
1404
1405 /* cull any connectors we created that don't have an encoder */
1406 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
1407 if (connector->encoder_ids[0])
1408 continue;
1409
1410 NV_WARN(dev, "%s has no encoders, removing\n",
1411 drm_get_connector_name(connector));
1412 connector->funcs->destroy(connector);
1413 }
1414
Ben Skeggs46005222011-07-05 11:01:13 +10001415 /* setup interrupt handling */
Ben Skeggsf20ce962011-07-08 13:17:01 +10001416 tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001417 nouveau_irq_register(dev, 26, nvd0_display_intr);
1418
Ben Skeggs51beb422011-07-05 10:33:08 +10001419 /* hash table and dma objects for the memory areas we care about */
Ben Skeggsefd272a2011-07-05 11:58:58 +10001420 ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000,
1421 NVOBJ_FLAG_ZERO_ALLOC, &disp->mem);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001422 if (ret)
1423 goto out;
1424
Ben Skeggsefd272a2011-07-05 11:58:58 +10001425 nv_wo32(disp->mem, 0x1000, 0x00000049);
1426 nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8);
1427 nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8);
1428 nv_wo32(disp->mem, 0x100c, 0x00000000);
1429 nv_wo32(disp->mem, 0x1010, 0x00000000);
1430 nv_wo32(disp->mem, 0x1014, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001431 nv_wo32(disp->mem, 0x0000, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001432 nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001);
1433
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001434 nv_wo32(disp->mem, 0x1020, 0x00000049);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001435 nv_wo32(disp->mem, 0x1024, 0x00000000);
1436 nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8);
1437 nv_wo32(disp->mem, 0x102c, 0x00000000);
1438 nv_wo32(disp->mem, 0x1030, 0x00000000);
1439 nv_wo32(disp->mem, 0x1034, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001440 nv_wo32(disp->mem, 0x0008, NvEvoVRAM);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001441 nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001);
1442
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001443 nv_wo32(disp->mem, 0x1040, 0x00000009);
1444 nv_wo32(disp->mem, 0x1044, 0x00000000);
1445 nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8);
1446 nv_wo32(disp->mem, 0x104c, 0x00000000);
1447 nv_wo32(disp->mem, 0x1050, 0x00000000);
1448 nv_wo32(disp->mem, 0x1054, 0x00000000);
1449 nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP);
1450 nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001);
1451
1452 nv_wo32(disp->mem, 0x1060, 0x0fe00009);
1453 nv_wo32(disp->mem, 0x1064, 0x00000000);
1454 nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8);
1455 nv_wo32(disp->mem, 0x106c, 0x00000000);
1456 nv_wo32(disp->mem, 0x1070, 0x00000000);
1457 nv_wo32(disp->mem, 0x1074, 0x00000000);
1458 nv_wo32(disp->mem, 0x0018, NvEvoFB32);
1459 nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001);
1460
Ben Skeggsefd272a2011-07-05 11:58:58 +10001461 pinstmem->flush(dev);
1462
Ben Skeggs51beb422011-07-05 10:33:08 +10001463 /* push buffers for evo channels */
1464 disp->evo[0].ptr =
1465 pci_alloc_consistent(pdev, PAGE_SIZE, &disp->evo[0].handle);
1466 if (!disp->evo[0].ptr) {
1467 ret = -ENOMEM;
1468 goto out;
1469 }
1470
Ben Skeggs26f6d882011-07-04 16:25:18 +10001471 ret = nvd0_display_init(dev);
1472 if (ret)
1473 goto out;
1474
1475out:
1476 if (ret)
1477 nvd0_display_destroy(dev);
1478 return ret;
1479}