blob: 649a4a6e9227e2aff603f35b41767ab99eca2785 [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
Ben Skeggsbdb8c212011-11-12 01:30:24 +100038#define EVO_MASTER (0x00)
39#define EVO_SYNC(c) (0x01 + (c))
40#define EVO_CURS(c) (0x0d + (c))
41
Ben Skeggs26f6d882011-07-04 16:25:18 +100042struct nvd0_display {
43 struct nouveau_gpuobj *mem;
Ben Skeggs51beb422011-07-05 10:33:08 +100044 struct {
45 dma_addr_t handle;
46 u32 *ptr;
Ben Skeggsbdb8c212011-11-12 01:30:24 +100047 } evo[3];
Ben Skeggsf20ce962011-07-08 13:17:01 +100048
49 struct tasklet_struct tasklet;
Ben Skeggsee417792011-07-08 14:34:45 +100050 u32 modeset;
Ben Skeggs26f6d882011-07-04 16:25:18 +100051};
52
53static struct nvd0_display *
54nvd0_display(struct drm_device *dev)
55{
56 struct drm_nouveau_private *dev_priv = dev->dev_private;
57 return dev_priv->engine.display.priv;
58}
59
Ben Skeggsbdb8c212011-11-12 01:30:24 +100060static struct drm_crtc *
61nvd0_display_crtc_get(struct drm_encoder *encoder)
62{
63 return nouveau_encoder(encoder)->crtc;
64}
65
66/******************************************************************************
67 * EVO channel helpers
68 *****************************************************************************/
Ben Skeggs37b034a2011-07-08 14:43:19 +100069static inline int
Ben Skeggs51beb422011-07-05 10:33:08 +100070evo_icmd(struct drm_device *dev, int id, u32 mthd, u32 data)
71{
72 int ret = 0;
73 nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000001);
74 nv_wr32(dev, 0x610704 + (id * 0x10), data);
75 nv_mask(dev, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd);
76 if (!nv_wait(dev, 0x610704 + (id * 0x10), 0x80000000, 0x00000000))
77 ret = -EBUSY;
78 nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000000);
79 return ret;
80}
81
82static u32 *
83evo_wait(struct drm_device *dev, int id, int nr)
84{
85 struct nvd0_display *disp = nvd0_display(dev);
86 u32 put = nv_rd32(dev, 0x640000 + (id * 0x1000)) / 4;
87
88 if (put + nr >= (PAGE_SIZE / 4)) {
89 disp->evo[id].ptr[put] = 0x20000000;
90
91 nv_wr32(dev, 0x640000 + (id * 0x1000), 0x00000000);
92 if (!nv_wait(dev, 0x640004 + (id * 0x1000), ~0, 0x00000000)) {
93 NV_ERROR(dev, "evo %d dma stalled\n", id);
94 return NULL;
95 }
96
97 put = 0;
98 }
99
Ben Skeggs27517dd2011-11-11 20:26:44 +1000100 if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
101 NV_INFO(dev, "Evo%d: %p START\n", id, disp->evo[id].ptr + put);
102
Ben Skeggs51beb422011-07-05 10:33:08 +1000103 return disp->evo[id].ptr + put;
104}
105
106static void
107evo_kick(u32 *push, struct drm_device *dev, int id)
108{
109 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs27517dd2011-11-11 20:26:44 +1000110
111 if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO) {
112 u32 curp = nv_rd32(dev, 0x640000 + (id * 0x1000)) >> 2;
113 u32 *cur = disp->evo[id].ptr + curp;
114
115 while (cur < push)
116 NV_INFO(dev, "Evo%d: 0x%08x\n", id, *cur++);
117 NV_INFO(dev, "Evo%d: %p KICK!\n", id, push);
118 }
119
Ben Skeggs51beb422011-07-05 10:33:08 +1000120 nv_wr32(dev, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2);
121}
122
123#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
124#define evo_data(p,d) *((p)++) = (d)
125
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000126static int
127evo_init_dma(struct drm_device *dev, int ch)
Ben Skeggs83fc0832011-07-05 13:08:40 +1000128{
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000129 struct nvd0_display *disp = nvd0_display(dev);
130 u32 flags;
131
132 flags = 0x00000000;
133 if (ch == EVO_MASTER)
134 flags |= 0x01000000;
135
136 nv_wr32(dev, 0x610494 + (ch * 0x0010), (disp->evo[ch].handle >> 8) | 3);
137 nv_wr32(dev, 0x610498 + (ch * 0x0010), 0x00010000);
138 nv_wr32(dev, 0x61049c + (ch * 0x0010), 0x00000001);
139 nv_mask(dev, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000010);
140 nv_wr32(dev, 0x640000 + (ch * 0x1000), 0x00000000);
141 nv_wr32(dev, 0x610490 + (ch * 0x0010), 0x00000013 | flags);
142 if (!nv_wait(dev, 0x610490 + (ch * 0x0010), 0x80000000, 0x00000000)) {
143 NV_ERROR(dev, "PDISP: ch%d 0x%08x\n", ch,
144 nv_rd32(dev, 0x610490 + (ch * 0x0010)));
145 return -EBUSY;
146 }
147
148 nv_mask(dev, 0x610090, (1 << ch), (1 << ch));
149 nv_mask(dev, 0x6100a0, (1 << ch), (1 << ch));
150 return 0;
151}
152
153static void
154evo_fini_dma(struct drm_device *dev, int ch)
155{
156 if (!(nv_rd32(dev, 0x610490 + (ch * 0x0010)) & 0x00000010))
157 return;
158
159 nv_mask(dev, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000000);
160 nv_mask(dev, 0x610490 + (ch * 0x0010), 0x00000003, 0x00000000);
161 nv_wait(dev, 0x610490 + (ch * 0x0010), 0x80000000, 0x00000000);
162 nv_mask(dev, 0x610090, (1 << ch), 0x00000000);
163 nv_mask(dev, 0x6100a0, (1 << ch), 0x00000000);
164}
165
166static int
167evo_init_pio(struct drm_device *dev, int ch)
168{
169 nv_wr32(dev, 0x610490 + (ch * 0x0010), 0x00000001);
170 if (!nv_wait(dev, 0x610490 + (ch * 0x0010), 0x00010000, 0x00010000)) {
171 NV_ERROR(dev, "PDISP: ch%d 0x%08x\n", ch,
172 nv_rd32(dev, 0x610490 + (ch * 0x0010)));
173 return -EBUSY;
174 }
175
176 nv_mask(dev, 0x610090, (1 << ch), (1 << ch));
177 nv_mask(dev, 0x6100a0, (1 << ch), (1 << ch));
178 return 0;
179}
180
181static void
182evo_fini_pio(struct drm_device *dev, int ch)
183{
184 if (!(nv_rd32(dev, 0x610490 + (ch * 0x0010)) & 0x00000001))
185 return;
186
187 nv_mask(dev, 0x610490 + (ch * 0x0010), 0x00000010, 0x00000010);
188 nv_mask(dev, 0x610490 + (ch * 0x0010), 0x00000001, 0x00000000);
189 nv_wait(dev, 0x610490 + (ch * 0x0010), 0x00010000, 0x00000000);
190 nv_mask(dev, 0x610090, (1 << ch), 0x00000000);
191 nv_mask(dev, 0x6100a0, (1 << ch), 0x00000000);
Ben Skeggs83fc0832011-07-05 13:08:40 +1000192}
193
Ben Skeggs26f6d882011-07-04 16:25:18 +1000194/******************************************************************************
Ben Skeggs438d99e2011-07-05 16:48:06 +1000195 * CRTC
196 *****************************************************************************/
197static int
Ben Skeggs488ff202011-10-17 10:38:10 +1000198nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000199{
200 struct drm_device *dev = nv_crtc->base.dev;
Ben Skeggsde691852011-10-17 12:23:41 +1000201 struct nouveau_connector *nv_connector;
202 struct drm_connector *connector;
203 u32 *push, mode = 0x00;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000204
Ben Skeggs488ff202011-10-17 10:38:10 +1000205 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsde691852011-10-17 12:23:41 +1000206 connector = &nv_connector->base;
207 if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
208 if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
209 mode = DITHERING_MODE_DYNAMIC2X2;
210 } else {
211 mode = nv_connector->dithering_mode;
212 }
213
214 if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) {
215 if (connector->display_info.bpc >= 8)
216 mode |= DITHERING_DEPTH_8BPC;
217 } else {
218 mode |= nv_connector->dithering_depth;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000219 }
220
221 push = evo_wait(dev, 0, 4);
222 if (push) {
223 evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1);
224 evo_data(push, mode);
225 if (update) {
226 evo_mthd(push, 0x0080, 1);
227 evo_data(push, 0x00000000);
228 }
229 evo_kick(push, dev, 0);
230 }
231
232 return 0;
233}
234
235static int
Ben Skeggs488ff202011-10-17 10:38:10 +1000236nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000237{
Ben Skeggs92854622011-11-11 23:49:06 +1000238 struct drm_display_mode *omode, *umode = &nv_crtc->base.mode;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000239 struct drm_device *dev = nv_crtc->base.dev;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000240 struct nouveau_connector *nv_connector;
Ben Skeggs92854622011-11-11 23:49:06 +1000241 int mode = DRM_MODE_SCALE_NONE;
242 u32 oX, oY, *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000243
Ben Skeggs92854622011-11-11 23:49:06 +1000244 /* start off at the resolution we programmed the crtc for, this
245 * effectively handles NONE/FULL scaling
246 */
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000247 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggs92854622011-11-11 23:49:06 +1000248 if (nv_connector && nv_connector->native_mode)
249 mode = nv_connector->scaling_mode;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000250
Ben Skeggs92854622011-11-11 23:49:06 +1000251 if (mode != DRM_MODE_SCALE_NONE)
252 omode = nv_connector->native_mode;
253 else
254 omode = umode;
255
256 oX = omode->hdisplay;
257 oY = omode->vdisplay;
258 if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
259 oY *= 2;
260
261 /* add overscan compensation if necessary, will keep the aspect
262 * ratio the same as the backend mode unless overridden by the
263 * user setting both hborder and vborder properties.
264 */
265 if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
266 (nv_connector->underscan == UNDERSCAN_AUTO &&
267 nv_connector->edid &&
268 drm_detect_hdmi_monitor(nv_connector->edid)))) {
269 u32 bX = nv_connector->underscan_hborder;
270 u32 bY = nv_connector->underscan_vborder;
271 u32 aspect = (oY << 19) / oX;
272
273 if (bX) {
274 oX -= (bX * 2);
275 if (bY) oY -= (bY * 2);
276 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
277 } else {
278 oX -= (oX >> 4) + 32;
279 if (bY) oY -= (bY * 2);
280 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000281 }
282 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000283
Ben Skeggs92854622011-11-11 23:49:06 +1000284 /* handle CENTER/ASPECT scaling, taking into account the areas
285 * removed already for overscan compensation
286 */
287 switch (mode) {
288 case DRM_MODE_SCALE_CENTER:
289 oX = min((u32)umode->hdisplay, oX);
290 oY = min((u32)umode->vdisplay, oY);
291 /* fall-through */
292 case DRM_MODE_SCALE_ASPECT:
293 if (oY < oX) {
294 u32 aspect = (umode->hdisplay << 19) / umode->vdisplay;
295 oX = ((oY * aspect) + (aspect / 2)) >> 19;
296 } else {
297 u32 aspect = (umode->vdisplay << 19) / umode->hdisplay;
298 oY = ((oX * aspect) + (aspect / 2)) >> 19;
299 }
300 break;
301 default:
302 break;
303 }
304
Ben Skeggs438d99e2011-07-05 16:48:06 +1000305 push = evo_wait(dev, 0, 16);
306 if (push) {
307 evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
Ben Skeggs92854622011-11-11 23:49:06 +1000308 evo_data(push, (oY << 16) | oX);
309 evo_data(push, (oY << 16) | oX);
310 evo_data(push, (oY << 16) | oX);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000311 evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
312 evo_data(push, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000313 evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
Ben Skeggs92854622011-11-11 23:49:06 +1000314 evo_data(push, (umode->vdisplay << 16) | umode->hdisplay);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000315 if (update) {
316 evo_mthd(push, 0x0080, 1);
317 evo_data(push, 0x00000000);
318 }
319 evo_kick(push, dev, 0);
320 }
321
322 return 0;
323}
324
325static int
326nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
327 int x, int y, bool update)
328{
329 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
330 u32 *push;
331
Ben Skeggs438d99e2011-07-05 16:48:06 +1000332 push = evo_wait(fb->dev, 0, 16);
333 if (push) {
334 evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1);
335 evo_data(push, nvfb->nvbo->bo.offset >> 8);
336 evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4);
337 evo_data(push, (fb->height << 16) | fb->width);
338 evo_data(push, nvfb->r_pitch);
339 evo_data(push, nvfb->r_format);
Ben Skeggsc0cc92a2011-07-06 11:40:45 +1000340 evo_data(push, nvfb->r_dma);
Ben Skeggsc6f2f712011-07-08 12:11:58 +1000341 evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1);
342 evo_data(push, (y << 16) | x);
Ben Skeggsa46232e2011-07-07 15:23:48 +1000343 if (update) {
344 evo_mthd(push, 0x0080, 1);
345 evo_data(push, 0x00000000);
346 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000347 evo_kick(push, fb->dev, 0);
348 }
349
Ben Skeggsc0cc92a2011-07-06 11:40:45 +1000350 nv_crtc->fb.tile_flags = nvfb->r_dma;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000351 return 0;
352}
353
354static void
355nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update)
356{
357 struct drm_device *dev = nv_crtc->base.dev;
358 u32 *push = evo_wait(dev, 0, 16);
359 if (push) {
360 if (show) {
361 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
362 evo_data(push, 0x85000000);
363 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
364 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +1000365 evo_data(push, NvEvoVRAM);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000366 } else {
367 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1);
368 evo_data(push, 0x05000000);
369 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
370 evo_data(push, 0x00000000);
371 }
372
373 if (update) {
374 evo_mthd(push, 0x0080, 1);
375 evo_data(push, 0x00000000);
376 }
377
378 evo_kick(push, dev, 0);
379 }
380}
381
382static void
383nvd0_crtc_dpms(struct drm_crtc *crtc, int mode)
384{
385}
386
387static void
388nvd0_crtc_prepare(struct drm_crtc *crtc)
389{
390 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
391 u32 *push;
392
393 push = evo_wait(crtc->dev, 0, 2);
394 if (push) {
395 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
396 evo_data(push, 0x00000000);
397 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1);
398 evo_data(push, 0x03000000);
399 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
400 evo_data(push, 0x00000000);
401 evo_kick(push, crtc->dev, 0);
402 }
403
404 nvd0_crtc_cursor_show(nv_crtc, false, false);
405}
406
407static void
408nvd0_crtc_commit(struct drm_crtc *crtc)
409{
410 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
411 u32 *push;
412
413 push = evo_wait(crtc->dev, 0, 32);
414 if (push) {
415 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
416 evo_data(push, nv_crtc->fb.tile_flags);
417 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4);
418 evo_data(push, 0x83000000);
419 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
420 evo_data(push, 0x00000000);
421 evo_data(push, 0x00000000);
422 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +1000423 evo_data(push, NvEvoVRAM);
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000424 evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1);
425 evo_data(push, 0xffffff00);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000426 evo_kick(push, crtc->dev, 0);
427 }
428
429 nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true);
430}
431
432static bool
433nvd0_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
434 struct drm_display_mode *adjusted_mode)
435{
436 return true;
437}
438
439static int
440nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
441{
442 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
443 int ret;
444
445 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
446 if (ret)
447 return ret;
448
449 if (old_fb) {
450 nvfb = nouveau_framebuffer(old_fb);
451 nouveau_bo_unpin(nvfb->nvbo);
452 }
453
454 return 0;
455}
456
457static int
458nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
459 struct drm_display_mode *mode, int x, int y,
460 struct drm_framebuffer *old_fb)
461{
462 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
463 struct nouveau_connector *nv_connector;
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000464 u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
465 u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
466 u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
467 u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
468 u32 vblan2e = 0, vblan2s = 1;
469 u32 magic = 0x31ec6000;
Ben Skeggs629c1b92011-07-08 09:43:20 +1000470 u32 syncs, *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000471 int ret;
472
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000473 hactive = mode->htotal;
474 hsynce = mode->hsync_end - mode->hsync_start - 1;
475 hbackp = mode->htotal - mode->hsync_end;
476 hblanke = hsynce + hbackp;
477 hfrontp = mode->hsync_start - mode->hdisplay;
478 hblanks = mode->htotal - hfrontp - 1;
479
480 vactive = mode->vtotal * vscan / ilace;
481 vsynce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
482 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
483 vblanke = vsynce + vbackp;
484 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
485 vblanks = vactive - vfrontp - 1;
486 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
487 vblan2e = vactive + vsynce + vbackp;
488 vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
489 vactive = (vactive * 2) + 1;
490 magic |= 0x00000001;
491 }
492
Ben Skeggs629c1b92011-07-08 09:43:20 +1000493 syncs = 0x00000001;
494 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
495 syncs |= 0x00000008;
496 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
497 syncs |= 0x00000010;
498
Ben Skeggs438d99e2011-07-05 16:48:06 +1000499 ret = nvd0_crtc_swap_fbs(crtc, old_fb);
500 if (ret)
501 return ret;
502
503 push = evo_wait(crtc->dev, 0, 64);
504 if (push) {
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000505 evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 6);
Ben Skeggs629c1b92011-07-08 09:43:20 +1000506 evo_data(push, 0x00000000);
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000507 evo_data(push, (vactive << 16) | hactive);
508 evo_data(push, ( vsynce << 16) | hsynce);
509 evo_data(push, (vblanke << 16) | hblanke);
510 evo_data(push, (vblanks << 16) | hblanks);
511 evo_data(push, (vblan2e << 16) | vblan2s);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000512 evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1);
513 evo_data(push, 0x00000000); /* ??? */
514 evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3);
515 evo_data(push, mode->clock * 1000);
516 evo_data(push, 0x00200000); /* ??? */
517 evo_data(push, mode->clock * 1000);
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000518 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
Ben Skeggs629c1b92011-07-08 09:43:20 +1000519 evo_data(push, syncs);
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000520 evo_data(push, magic);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000521 evo_kick(push, crtc->dev, 0);
522 }
523
524 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggs488ff202011-10-17 10:38:10 +1000525 nvd0_crtc_set_dither(nv_crtc, false);
526 nvd0_crtc_set_scale(nv_crtc, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000527 nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
528 return 0;
529}
530
531static int
532nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
533 struct drm_framebuffer *old_fb)
534{
535 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
536 int ret;
537
Ben Skeggs84e2ad82011-08-26 09:40:39 +1000538 if (!crtc->fb) {
539 NV_DEBUG_KMS(crtc->dev, "No FB bound\n");
540 return 0;
541 }
542
Ben Skeggs438d99e2011-07-05 16:48:06 +1000543 ret = nvd0_crtc_swap_fbs(crtc, old_fb);
544 if (ret)
545 return ret;
546
547 nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
548 return 0;
549}
550
551static int
552nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
553 struct drm_framebuffer *fb, int x, int y,
554 enum mode_set_atomic state)
555{
556 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
557 nvd0_crtc_set_image(nv_crtc, fb, x, y, true);
558 return 0;
559}
560
561static void
562nvd0_crtc_lut_load(struct drm_crtc *crtc)
563{
564 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
565 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
566 int i;
567
568 for (i = 0; i < 256; i++) {
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000569 writew(0x6000 + (nv_crtc->lut.r[i] >> 2), lut + (i * 0x20) + 0);
570 writew(0x6000 + (nv_crtc->lut.g[i] >> 2), lut + (i * 0x20) + 2);
571 writew(0x6000 + (nv_crtc->lut.b[i] >> 2), lut + (i * 0x20) + 4);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000572 }
573}
574
575static int
576nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
577 uint32_t handle, uint32_t width, uint32_t height)
578{
579 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
580 struct drm_device *dev = crtc->dev;
581 struct drm_gem_object *gem;
582 struct nouveau_bo *nvbo;
583 bool visible = (handle != 0);
584 int i, ret = 0;
585
586 if (visible) {
587 if (width != 64 || height != 64)
588 return -EINVAL;
589
590 gem = drm_gem_object_lookup(dev, file_priv, handle);
591 if (unlikely(!gem))
592 return -ENOENT;
593 nvbo = nouveau_gem_object(gem);
594
595 ret = nouveau_bo_map(nvbo);
596 if (ret == 0) {
597 for (i = 0; i < 64 * 64; i++) {
598 u32 v = nouveau_bo_rd32(nvbo, i);
599 nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v);
600 }
601 nouveau_bo_unmap(nvbo);
602 }
603
604 drm_gem_object_unreference_unlocked(gem);
605 }
606
607 if (visible != nv_crtc->cursor.visible) {
608 nvd0_crtc_cursor_show(nv_crtc, visible, true);
609 nv_crtc->cursor.visible = visible;
610 }
611
612 return ret;
613}
614
615static int
616nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
617{
618 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
619 const u32 data = (y << 16) | x;
620
621 nv_wr32(crtc->dev, 0x64d084 + (nv_crtc->index * 0x1000), data);
622 nv_wr32(crtc->dev, 0x64d080 + (nv_crtc->index * 0x1000), 0x00000000);
623 return 0;
624}
625
626static void
627nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
628 uint32_t start, uint32_t size)
629{
630 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
631 u32 end = max(start + size, (u32)256);
632 u32 i;
633
634 for (i = start; i < end; i++) {
635 nv_crtc->lut.r[i] = r[i];
636 nv_crtc->lut.g[i] = g[i];
637 nv_crtc->lut.b[i] = b[i];
638 }
639
640 nvd0_crtc_lut_load(crtc);
641}
642
643static void
644nvd0_crtc_destroy(struct drm_crtc *crtc)
645{
646 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
647 nouveau_bo_unmap(nv_crtc->cursor.nvbo);
648 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
649 nouveau_bo_unmap(nv_crtc->lut.nvbo);
650 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
651 drm_crtc_cleanup(crtc);
652 kfree(crtc);
653}
654
655static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = {
656 .dpms = nvd0_crtc_dpms,
657 .prepare = nvd0_crtc_prepare,
658 .commit = nvd0_crtc_commit,
659 .mode_fixup = nvd0_crtc_mode_fixup,
660 .mode_set = nvd0_crtc_mode_set,
661 .mode_set_base = nvd0_crtc_mode_set_base,
662 .mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic,
663 .load_lut = nvd0_crtc_lut_load,
664};
665
666static const struct drm_crtc_funcs nvd0_crtc_func = {
667 .cursor_set = nvd0_crtc_cursor_set,
668 .cursor_move = nvd0_crtc_cursor_move,
669 .gamma_set = nvd0_crtc_gamma_set,
670 .set_config = drm_crtc_helper_set_config,
671 .destroy = nvd0_crtc_destroy,
672};
673
Ben Skeggsc20ab3e2011-08-25 14:09:43 +1000674static void
675nvd0_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
676{
677}
678
679static void
680nvd0_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
681{
682}
683
Ben Skeggs438d99e2011-07-05 16:48:06 +1000684static int
685nvd0_crtc_create(struct drm_device *dev, int index)
686{
687 struct nouveau_crtc *nv_crtc;
688 struct drm_crtc *crtc;
689 int ret, i;
690
691 nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
692 if (!nv_crtc)
693 return -ENOMEM;
694
695 nv_crtc->index = index;
696 nv_crtc->set_dither = nvd0_crtc_set_dither;
697 nv_crtc->set_scale = nvd0_crtc_set_scale;
Ben Skeggsc20ab3e2011-08-25 14:09:43 +1000698 nv_crtc->cursor.set_offset = nvd0_cursor_set_offset;
699 nv_crtc->cursor.set_pos = nvd0_cursor_set_pos;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000700 for (i = 0; i < 256; i++) {
701 nv_crtc->lut.r[i] = i << 8;
702 nv_crtc->lut.g[i] = i << 8;
703 nv_crtc->lut.b[i] = i << 8;
704 }
705
706 crtc = &nv_crtc->base;
707 drm_crtc_init(dev, crtc, &nvd0_crtc_func);
708 drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc);
709 drm_mode_crtc_set_gamma_size(crtc, 256);
710
711 ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
712 0, 0x0000, &nv_crtc->cursor.nvbo);
713 if (!ret) {
714 ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
715 if (!ret)
716 ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
717 if (ret)
718 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
719 }
720
721 if (ret)
722 goto out;
723
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +1000724 ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
Ben Skeggs438d99e2011-07-05 16:48:06 +1000725 0, 0x0000, &nv_crtc->lut.nvbo);
726 if (!ret) {
727 ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
728 if (!ret)
729 ret = nouveau_bo_map(nv_crtc->lut.nvbo);
730 if (ret)
731 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
732 }
733
734 if (ret)
735 goto out;
736
737 nvd0_crtc_lut_load(crtc);
738
739out:
740 if (ret)
741 nvd0_crtc_destroy(crtc);
742 return ret;
743}
744
745/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +1000746 * DAC
747 *****************************************************************************/
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000748static void
749nvd0_dac_dpms(struct drm_encoder *encoder, int mode)
750{
751 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
752 struct drm_device *dev = encoder->dev;
753 int or = nv_encoder->or;
754 u32 dpms_ctrl;
755
756 dpms_ctrl = 0x80000000;
757 if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF)
758 dpms_ctrl |= 0x00000001;
759 if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF)
760 dpms_ctrl |= 0x00000004;
761
762 nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
763 nv_mask(dev, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl);
764 nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000);
765}
766
767static bool
768nvd0_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
769 struct drm_display_mode *adjusted_mode)
770{
771 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
772 struct nouveau_connector *nv_connector;
773
774 nv_connector = nouveau_encoder_connector_get(nv_encoder);
775 if (nv_connector && nv_connector->native_mode) {
776 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
777 int id = adjusted_mode->base.id;
778 *adjusted_mode = *nv_connector->native_mode;
779 adjusted_mode->base.id = id;
780 }
781 }
782
783 return true;
784}
785
786static void
787nvd0_dac_prepare(struct drm_encoder *encoder)
788{
789}
790
791static void
792nvd0_dac_commit(struct drm_encoder *encoder)
793{
794}
795
796static void
797nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
798 struct drm_display_mode *adjusted_mode)
799{
800 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
801 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
802 u32 *push;
803
804 nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON);
805
Ben Skeggsff8ff502011-07-08 11:53:37 +1000806 push = evo_wait(encoder->dev, 0, 4);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000807 if (push) {
Ben Skeggsff8ff502011-07-08 11:53:37 +1000808 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000809 evo_data(push, 1 << nv_crtc->index);
Ben Skeggsff8ff502011-07-08 11:53:37 +1000810 evo_data(push, 0x00ff);
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000811 evo_kick(push, encoder->dev, 0);
812 }
813
814 nv_encoder->crtc = encoder->crtc;
815}
816
817static void
818nvd0_dac_disconnect(struct drm_encoder *encoder)
819{
820 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
821 struct drm_device *dev = encoder->dev;
822 u32 *push;
823
824 if (nv_encoder->crtc) {
825 nvd0_crtc_prepare(nv_encoder->crtc);
826
827 push = evo_wait(dev, 0, 4);
828 if (push) {
829 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 1);
830 evo_data(push, 0x00000000);
831 evo_mthd(push, 0x0080, 1);
832 evo_data(push, 0x00000000);
833 evo_kick(push, dev, 0);
834 }
835
836 nv_encoder->crtc = NULL;
837 }
838}
839
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000840static enum drm_connector_status
841nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
842{
Ben Skeggsb6819932011-07-08 11:14:50 +1000843 enum drm_connector_status status = connector_status_disconnected;
844 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
845 struct drm_device *dev = encoder->dev;
846 int or = nv_encoder->or;
847 u32 load;
848
849 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00100000);
850 udelay(9500);
851 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x80000000);
852
853 load = nv_rd32(dev, 0x61a00c + (or * 0x800));
854 if ((load & 0x38000000) == 0x38000000)
855 status = connector_status_connected;
856
857 nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00000000);
858 return status;
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000859}
860
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000861static void
862nvd0_dac_destroy(struct drm_encoder *encoder)
863{
864 drm_encoder_cleanup(encoder);
865 kfree(encoder);
866}
867
868static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = {
869 .dpms = nvd0_dac_dpms,
870 .mode_fixup = nvd0_dac_mode_fixup,
871 .prepare = nvd0_dac_prepare,
872 .commit = nvd0_dac_commit,
873 .mode_set = nvd0_dac_mode_set,
874 .disable = nvd0_dac_disconnect,
875 .get_crtc = nvd0_display_crtc_get,
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +1000876 .detect = nvd0_dac_detect
Ben Skeggs8eaa9662011-07-06 15:25:47 +1000877};
878
879static const struct drm_encoder_funcs nvd0_dac_func = {
880 .destroy = nvd0_dac_destroy,
881};
882
883static int
884nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe)
885{
886 struct drm_device *dev = connector->dev;
887 struct nouveau_encoder *nv_encoder;
888 struct drm_encoder *encoder;
889
890 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
891 if (!nv_encoder)
892 return -ENOMEM;
893 nv_encoder->dcb = dcbe;
894 nv_encoder->or = ffs(dcbe->or) - 1;
895
896 encoder = to_drm_encoder(nv_encoder);
897 encoder->possible_crtcs = dcbe->heads;
898 encoder->possible_clones = 0;
899 drm_encoder_init(dev, encoder, &nvd0_dac_func, DRM_MODE_ENCODER_DAC);
900 drm_encoder_helper_add(encoder, &nvd0_dac_hfunc);
901
902 drm_mode_connector_attach_encoder(connector, encoder);
903 return 0;
904}
Ben Skeggs26f6d882011-07-04 16:25:18 +1000905
906/******************************************************************************
Ben Skeggs78951d22011-11-11 18:13:13 +1000907 * Audio
908 *****************************************************************************/
909static void
910nvd0_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
911{
912 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
913 struct nouveau_connector *nv_connector;
914 struct drm_device *dev = encoder->dev;
915 int i, or = nv_encoder->or * 0x30;
916
917 nv_connector = nouveau_encoder_connector_get(nv_encoder);
918 if (!drm_detect_monitor_audio(nv_connector->edid))
919 return;
920
921 nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000001);
922
923 drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
924 if (nv_connector->base.eld[0]) {
925 u8 *eld = nv_connector->base.eld;
926
927 for (i = 0; i < eld[2] * 4; i++)
928 nv_wr32(dev, 0x10ec00 + or, (i << 8) | eld[i]);
929 for (i = eld[2] * 4; i < 0x60; i++)
930 nv_wr32(dev, 0x10ec00 + or, (i << 8) | 0x00);
931
932 nv_mask(dev, 0x10ec10 + or, 0x80000002, 0x80000002);
933 }
934}
935
936static void
937nvd0_audio_disconnect(struct drm_encoder *encoder)
938{
939 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
940 struct drm_device *dev = encoder->dev;
941 int or = nv_encoder->or * 0x30;
942
943 nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000000);
944}
945
946/******************************************************************************
947 * HDMI
948 *****************************************************************************/
949static void
950nvd0_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
951{
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000952 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
953 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
954 struct nouveau_connector *nv_connector;
955 struct drm_device *dev = encoder->dev;
956 int head = nv_crtc->index * 0x800;
957 u32 rekey = 56; /* binary driver, and tegra constant */
958 u32 max_ac_packet;
959
960 nv_connector = nouveau_encoder_connector_get(nv_encoder);
961 if (!drm_detect_hdmi_monitor(nv_connector->edid))
962 return;
963
964 max_ac_packet = mode->htotal - mode->hdisplay;
965 max_ac_packet -= rekey;
966 max_ac_packet -= 18; /* constant from tegra */
967 max_ac_packet /= 32;
968
969 /* AVI InfoFrame */
970 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000000);
971 nv_wr32(dev, 0x61671c + head, 0x000d0282);
972 nv_wr32(dev, 0x616720 + head, 0x0000006f);
973 nv_wr32(dev, 0x616724 + head, 0x00000000);
974 nv_wr32(dev, 0x616728 + head, 0x00000000);
975 nv_wr32(dev, 0x61672c + head, 0x00000000);
976 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000001);
977
978 /* ??? InfoFrame? */
979 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000000);
980 nv_wr32(dev, 0x6167ac + head, 0x00000010);
981 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000001);
982
983 /* HDMI_CTRL */
984 nv_mask(dev, 0x616798 + head, 0x401f007f, 0x40000000 | rekey |
985 max_ac_packet << 16);
986
Ben Skeggs091e40c2011-11-11 20:46:00 +1000987 /* NFI, audio doesn't work without it though.. */
988 nv_mask(dev, 0x616548 + head, 0x00000070, 0x00000000);
989
Ben Skeggs78951d22011-11-11 18:13:13 +1000990 nvd0_audio_mode_set(encoder, mode);
991}
992
993static void
994nvd0_hdmi_disconnect(struct drm_encoder *encoder)
995{
Ben Skeggs64d9cc02011-11-11 19:51:20 +1000996 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
997 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
998 struct drm_device *dev = encoder->dev;
999 int head = nv_crtc->index * 0x800;
1000
Ben Skeggs78951d22011-11-11 18:13:13 +10001001 nvd0_audio_disconnect(encoder);
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001002
1003 nv_mask(dev, 0x616798 + head, 0x40000000, 0x00000000);
1004 nv_mask(dev, 0x6167a4 + head, 0x00000001, 0x00000000);
1005 nv_mask(dev, 0x616714 + head, 0x00000001, 0x00000000);
Ben Skeggs78951d22011-11-11 18:13:13 +10001006}
1007
1008/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10001009 * SOR
1010 *****************************************************************************/
Ben Skeggs83fc0832011-07-05 13:08:40 +10001011static void
1012nvd0_sor_dpms(struct drm_encoder *encoder, int mode)
1013{
1014 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1015 struct drm_device *dev = encoder->dev;
1016 struct drm_encoder *partner;
1017 int or = nv_encoder->or;
1018 u32 dpms_ctrl;
1019
1020 nv_encoder->last_dpms = mode;
1021
1022 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
1023 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
1024
1025 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
1026 continue;
1027
1028 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +10001029 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +10001030 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
1031 return;
1032 break;
1033 }
1034 }
1035
1036 dpms_ctrl = (mode == DRM_MODE_DPMS_ON);
1037 dpms_ctrl |= 0x80000000;
1038
1039 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
1040 nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl);
1041 nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000);
1042 nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000);
1043}
1044
1045static bool
1046nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
1047 struct drm_display_mode *adjusted_mode)
1048{
1049 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1050 struct nouveau_connector *nv_connector;
1051
1052 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1053 if (nv_connector && nv_connector->native_mode) {
1054 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
1055 int id = adjusted_mode->base.id;
1056 *adjusted_mode = *nv_connector->native_mode;
1057 adjusted_mode->base.id = id;
1058 }
1059 }
1060
1061 return true;
1062}
1063
1064static void
1065nvd0_sor_prepare(struct drm_encoder *encoder)
1066{
1067}
1068
1069static void
1070nvd0_sor_commit(struct drm_encoder *encoder)
1071{
1072}
1073
1074static void
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001075nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
1076 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001077{
Ben Skeggs78951d22011-11-11 18:13:13 +10001078 struct drm_device *dev = encoder->dev;
1079 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001080 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1081 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001082 struct nouveau_connector *nv_connector;
1083 struct nvbios *bios = &dev_priv->vbios;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001084 u32 mode_ctrl = (1 << nv_crtc->index);
Ben Skeggsff8ff502011-07-08 11:53:37 +10001085 u32 *push, or_config;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001086
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001087 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1088 switch (nv_encoder->dcb->type) {
1089 case OUTPUT_TMDS:
1090 if (nv_encoder->dcb->sorconf.link & 1) {
1091 if (mode->clock < 165000)
1092 mode_ctrl |= 0x00000100;
1093 else
1094 mode_ctrl |= 0x00000500;
1095 } else {
1096 mode_ctrl |= 0x00000200;
1097 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10001098
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001099 or_config = (mode_ctrl & 0x00000f00) >> 8;
1100 if (mode->clock >= 165000)
1101 or_config |= 0x0100;
Ben Skeggs78951d22011-11-11 18:13:13 +10001102
1103 nvd0_hdmi_mode_set(encoder, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001104 break;
1105 case OUTPUT_LVDS:
1106 or_config = (mode_ctrl & 0x00000f00) >> 8;
1107 if (bios->fp_no_ddc) {
1108 if (bios->fp.dual_link)
1109 or_config |= 0x0100;
1110 if (bios->fp.if_is_24bit)
1111 or_config |= 0x0200;
1112 } else {
1113 if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
1114 if (((u8 *)nv_connector->edid)[121] == 2)
1115 or_config |= 0x0100;
1116 } else
1117 if (mode->clock >= bios->fp.duallink_transition_clk) {
1118 or_config |= 0x0100;
1119 }
1120
1121 if (or_config & 0x0100) {
1122 if (bios->fp.strapless_is_24bit & 2)
1123 or_config |= 0x0200;
1124 } else {
1125 if (bios->fp.strapless_is_24bit & 1)
1126 or_config |= 0x0200;
1127 }
1128
1129 if (nv_connector->base.display_info.bpc == 8)
1130 or_config |= 0x0200;
1131
1132 }
1133 break;
1134 default:
1135 BUG_ON(1);
1136 break;
1137 }
Ben Skeggsff8ff502011-07-08 11:53:37 +10001138
Ben Skeggs83fc0832011-07-05 13:08:40 +10001139 nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON);
1140
Ben Skeggs78951d22011-11-11 18:13:13 +10001141 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001142 if (push) {
Ben Skeggsff8ff502011-07-08 11:53:37 +10001143 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001144 evo_data(push, mode_ctrl);
Ben Skeggsff8ff502011-07-08 11:53:37 +10001145 evo_data(push, or_config);
Ben Skeggs78951d22011-11-11 18:13:13 +10001146 evo_kick(push, dev, 0);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001147 }
1148
1149 nv_encoder->crtc = encoder->crtc;
1150}
1151
1152static void
1153nvd0_sor_disconnect(struct drm_encoder *encoder)
1154{
1155 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1156 struct drm_device *dev = encoder->dev;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001157 u32 *push;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001158
1159 if (nv_encoder->crtc) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10001160 nvd0_crtc_prepare(nv_encoder->crtc);
1161
1162 push = evo_wait(dev, 0, 4);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001163 if (push) {
1164 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
1165 evo_data(push, 0x00000000);
1166 evo_mthd(push, 0x0080, 1);
1167 evo_data(push, 0x00000000);
1168 evo_kick(push, dev, 0);
1169 }
1170
Ben Skeggs78951d22011-11-11 18:13:13 +10001171 nvd0_hdmi_disconnect(encoder);
1172
Ben Skeggs83fc0832011-07-05 13:08:40 +10001173 nv_encoder->crtc = NULL;
1174 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1175 }
1176}
1177
1178static void
1179nvd0_sor_destroy(struct drm_encoder *encoder)
1180{
1181 drm_encoder_cleanup(encoder);
1182 kfree(encoder);
1183}
1184
1185static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = {
1186 .dpms = nvd0_sor_dpms,
1187 .mode_fixup = nvd0_sor_mode_fixup,
1188 .prepare = nvd0_sor_prepare,
1189 .commit = nvd0_sor_commit,
1190 .mode_set = nvd0_sor_mode_set,
1191 .disable = nvd0_sor_disconnect,
1192 .get_crtc = nvd0_display_crtc_get,
1193};
1194
1195static const struct drm_encoder_funcs nvd0_sor_func = {
1196 .destroy = nvd0_sor_destroy,
1197};
1198
1199static int
1200nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe)
1201{
1202 struct drm_device *dev = connector->dev;
1203 struct nouveau_encoder *nv_encoder;
1204 struct drm_encoder *encoder;
1205
1206 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
1207 if (!nv_encoder)
1208 return -ENOMEM;
1209 nv_encoder->dcb = dcbe;
1210 nv_encoder->or = ffs(dcbe->or) - 1;
1211 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1212
1213 encoder = to_drm_encoder(nv_encoder);
1214 encoder->possible_crtcs = dcbe->heads;
1215 encoder->possible_clones = 0;
1216 drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS);
1217 drm_encoder_helper_add(encoder, &nvd0_sor_hfunc);
1218
1219 drm_mode_connector_attach_encoder(connector, encoder);
1220 return 0;
1221}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001222
1223/******************************************************************************
1224 * IRQ
1225 *****************************************************************************/
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001226static struct dcb_entry *
1227lookup_dcb(struct drm_device *dev, int id, u32 mc)
1228{
1229 struct drm_nouveau_private *dev_priv = dev->dev_private;
1230 int type, or, i;
1231
1232 if (id < 4) {
1233 type = OUTPUT_ANALOG;
1234 or = id;
1235 } else {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001236 switch (mc & 0x00000f00) {
1237 case 0x00000000: type = OUTPUT_LVDS; break;
1238 case 0x00000100: type = OUTPUT_TMDS; break;
1239 case 0x00000200: type = OUTPUT_TMDS; break;
1240 case 0x00000500: type = OUTPUT_TMDS; break;
1241 default:
Ben Skeggsee417792011-07-08 14:34:45 +10001242 NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001243 return NULL;
1244 }
1245
1246 or = id - 4;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001247 }
1248
1249 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
1250 struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
1251 if (dcb->type == type && (dcb->or & (1 << or)))
1252 return dcb;
1253 }
1254
Ben Skeggsee417792011-07-08 14:34:45 +10001255 NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001256 return NULL;
1257}
1258
Ben Skeggs46005222011-07-05 11:01:13 +10001259static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001260nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001261{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001262 struct dcb_entry *dcb;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001263 int i;
1264
Ben Skeggsee417792011-07-08 14:34:45 +10001265 for (i = 0; mask && i < 8; i++) {
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001266 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
Ben Skeggsee417792011-07-08 14:34:45 +10001267 if (!(mcc & (1 << crtc)))
1268 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001269
Ben Skeggsee417792011-07-08 14:34:45 +10001270 dcb = lookup_dcb(dev, i, mcc);
1271 if (!dcb)
1272 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001273
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001274 nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001275 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001276
Ben Skeggs270a5742011-07-05 14:16:05 +10001277 nv_wr32(dev, 0x6101d4, 0x00000000);
1278 nv_wr32(dev, 0x6109d4, 0x00000000);
1279 nv_wr32(dev, 0x6101d0, 0x80000000);
1280}
1281
1282static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001283nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001284{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001285 struct dcb_entry *dcb;
Ben Skeggs37b034a2011-07-08 14:43:19 +10001286 u32 or, tmp, pclk;
Ben Skeggsee417792011-07-08 14:34:45 +10001287 int i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001288
Ben Skeggsee417792011-07-08 14:34:45 +10001289 for (i = 0; mask && i < 8; i++) {
1290 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
1291 if (!(mcc & (1 << crtc)))
1292 continue;
1293
1294 dcb = lookup_dcb(dev, i, mcc);
1295 if (!dcb)
1296 continue;
1297
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001298 nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc);
Ben Skeggsee417792011-07-08 14:34:45 +10001299 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001300
Ben Skeggsee417792011-07-08 14:34:45 +10001301 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
1302 if (mask & 0x00010000) {
1303 nv50_crtc_set_clock(dev, crtc, pclk);
1304 }
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001305
Ben Skeggsee417792011-07-08 14:34:45 +10001306 for (i = 0; mask && i < 8; i++) {
1307 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1308 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1309 if (!(mcp & (1 << crtc)))
1310 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001311
Ben Skeggsee417792011-07-08 14:34:45 +10001312 dcb = lookup_dcb(dev, i, mcp);
1313 if (!dcb)
1314 continue;
1315 or = ffs(dcb->or) - 1;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001316
Ben Skeggsee417792011-07-08 14:34:45 +10001317 nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc);
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001318
Ben Skeggsee417792011-07-08 14:34:45 +10001319 nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000);
1320 switch (dcb->type) {
1321 case OUTPUT_ANALOG:
1322 nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000);
1323 break;
1324 case OUTPUT_TMDS:
1325 case OUTPUT_LVDS:
1326 if (cfg & 0x00000100)
1327 tmp = 0x00000101;
1328 else
1329 tmp = 0x00000000;
1330
1331 nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
1332 break;
1333 default:
1334 break;
1335 }
1336
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001337 break;
1338 }
1339
Ben Skeggs270a5742011-07-05 14:16:05 +10001340 nv_wr32(dev, 0x6101d4, 0x00000000);
1341 nv_wr32(dev, 0x6109d4, 0x00000000);
1342 nv_wr32(dev, 0x6101d0, 0x80000000);
1343}
1344
1345static void
Ben Skeggs37b034a2011-07-08 14:43:19 +10001346nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask)
Ben Skeggs270a5742011-07-05 14:16:05 +10001347{
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001348 struct dcb_entry *dcb;
Ben Skeggsee417792011-07-08 14:34:45 +10001349 int pclk, i;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001350
Ben Skeggsee417792011-07-08 14:34:45 +10001351 pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001352
Ben Skeggsee417792011-07-08 14:34:45 +10001353 for (i = 0; mask && i < 8; i++) {
1354 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
1355 u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20));
1356 if (!(mcp & (1 << crtc)))
1357 continue;
Ben Skeggs3a89cd02011-07-07 10:47:10 +10001358
Ben Skeggsee417792011-07-08 14:34:45 +10001359 dcb = lookup_dcb(dev, i, mcp);
1360 if (!dcb)
1361 continue;
1362
1363 nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc);
1364 }
1365
Ben Skeggs270a5742011-07-05 14:16:05 +10001366 nv_wr32(dev, 0x6101d4, 0x00000000);
1367 nv_wr32(dev, 0x6109d4, 0x00000000);
1368 nv_wr32(dev, 0x6101d0, 0x80000000);
1369}
1370
1371static void
Ben Skeggsf20ce962011-07-08 13:17:01 +10001372nvd0_display_bh(unsigned long data)
1373{
1374 struct drm_device *dev = (struct drm_device *)data;
1375 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001376 u32 mask, crtc;
1377 int i;
1378
1379 if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) {
1380 NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset);
1381 NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n",
1382 nv_rd32(dev, 0x6101d0),
1383 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
1384 for (i = 0; i < 8; i++) {
1385 NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n",
1386 i < 4 ? "DAC" : "SOR", i,
1387 nv_rd32(dev, 0x640180 + (i * 0x20)),
1388 nv_rd32(dev, 0x660180 + (i * 0x20)));
1389 }
1390 }
1391
1392 mask = nv_rd32(dev, 0x6101d4);
1393 crtc = 0;
1394 if (!mask) {
1395 mask = nv_rd32(dev, 0x6109d4);
1396 crtc = 1;
1397 }
Ben Skeggsf20ce962011-07-08 13:17:01 +10001398
Ben Skeggsee417792011-07-08 14:34:45 +10001399 if (disp->modeset & 0x00000001)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001400 nvd0_display_unk1_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001401 if (disp->modeset & 0x00000002)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001402 nvd0_display_unk2_handler(dev, crtc, mask);
Ben Skeggsee417792011-07-08 14:34:45 +10001403 if (disp->modeset & 0x00000004)
Ben Skeggs37b034a2011-07-08 14:43:19 +10001404 nvd0_display_unk4_handler(dev, crtc, mask);
Ben Skeggsf20ce962011-07-08 13:17:01 +10001405}
1406
1407static void
Ben Skeggs46005222011-07-05 11:01:13 +10001408nvd0_display_intr(struct drm_device *dev)
1409{
Ben Skeggsf20ce962011-07-08 13:17:01 +10001410 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001411 u32 intr = nv_rd32(dev, 0x610088);
1412
1413 if (intr & 0x00000002) {
1414 u32 stat = nv_rd32(dev, 0x61009c);
1415 int chid = ffs(stat) - 1;
1416 if (chid >= 0) {
1417 u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12));
1418 u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12));
1419 u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12));
1420
1421 NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x "
1422 "0x%08x 0x%08x\n",
1423 chid, (mthd & 0x0000ffc), data, mthd, unkn);
1424 nv_wr32(dev, 0x61009c, (1 << chid));
1425 nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000);
1426 }
1427
1428 intr &= ~0x00000002;
1429 }
1430
Ben Skeggs270a5742011-07-05 14:16:05 +10001431 if (intr & 0x00100000) {
1432 u32 stat = nv_rd32(dev, 0x6100ac);
1433
1434 if (stat & 0x00000007) {
Ben Skeggsee417792011-07-08 14:34:45 +10001435 disp->modeset = stat;
Ben Skeggsf20ce962011-07-08 13:17:01 +10001436 tasklet_schedule(&disp->tasklet);
Ben Skeggs270a5742011-07-05 14:16:05 +10001437
Ben Skeggsf20ce962011-07-08 13:17:01 +10001438 nv_wr32(dev, 0x6100ac, (stat & 0x00000007));
Ben Skeggs270a5742011-07-05 14:16:05 +10001439 stat &= ~0x00000007;
1440 }
1441
1442 if (stat) {
1443 NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat);
1444 nv_wr32(dev, 0x6100ac, stat);
1445 }
1446
1447 intr &= ~0x00100000;
1448 }
1449
Ben Skeggs46005222011-07-05 11:01:13 +10001450 if (intr & 0x01000000) {
1451 u32 stat = nv_rd32(dev, 0x6100bc);
1452 nv_wr32(dev, 0x6100bc, stat);
1453 intr &= ~0x01000000;
1454 }
1455
1456 if (intr & 0x02000000) {
1457 u32 stat = nv_rd32(dev, 0x6108bc);
1458 nv_wr32(dev, 0x6108bc, stat);
1459 intr &= ~0x02000000;
1460 }
1461
1462 if (intr)
1463 NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr);
1464}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001465
1466/******************************************************************************
1467 * Init
1468 *****************************************************************************/
Ben Skeggs2a44e492011-11-09 11:36:33 +10001469void
Ben Skeggs26f6d882011-07-04 16:25:18 +10001470nvd0_display_fini(struct drm_device *dev)
1471{
1472 int i;
1473
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001474 /* fini cursors + syncs */
1475 for (i = 1; i >= 0; i--) {
1476 evo_fini_pio(dev, EVO_CURS(i));
1477 evo_fini_dma(dev, EVO_SYNC(i));
Ben Skeggs26f6d882011-07-04 16:25:18 +10001478 }
1479
1480 /* fini master */
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001481 evo_fini_dma(dev, EVO_MASTER);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001482}
1483
1484int
1485nvd0_display_init(struct drm_device *dev)
1486{
1487 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001488 int ret, i;
Ben Skeggsefd272a2011-07-05 11:58:58 +10001489 u32 *push;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001490
1491 if (nv_rd32(dev, 0x6100ac) & 0x00000100) {
1492 nv_wr32(dev, 0x6100ac, 0x00000100);
1493 nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000);
1494 if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) {
1495 NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n",
1496 nv_rd32(dev, 0x6194e8));
1497 return -EBUSY;
1498 }
1499 }
1500
Ben Skeggsa36f04c2011-07-06 14:39:23 +10001501 /* nfi what these are exactly, i do know that SOR_MODE_CTRL won't
1502 * work at all unless you do the SOR part below.
1503 */
1504 for (i = 0; i < 3; i++) {
1505 u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800));
1506 nv_wr32(dev, 0x6101c0 + (i * 0x800), dac);
1507 }
1508
1509 for (i = 0; i < 4; i++) {
1510 u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800));
1511 nv_wr32(dev, 0x6301c4 + (i * 0x800), sor);
1512 }
1513
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001514 for (i = 0; i < dev->mode_config.num_crtc; i++) {
Ben Skeggsa36f04c2011-07-06 14:39:23 +10001515 u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800));
1516 u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800));
1517 u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800));
1518 nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0);
1519 nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1);
1520 nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2);
1521 }
1522
1523 /* point at our hash table / objects, enable interrupts */
Ben Skeggs26f6d882011-07-04 16:25:18 +10001524 nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9);
Ben Skeggs270a5742011-07-05 14:16:05 +10001525 nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001526
1527 /* init master */
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001528 ret = evo_init_dma(dev, EVO_MASTER);
1529 if (ret)
1530 goto error;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001531
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001532 /* init syncs + cursors */
1533 for (i = 0; i < dev->mode_config.num_crtc; i++) {
1534 if ((ret = evo_init_dma(dev, EVO_SYNC(i))) ||
1535 (ret = evo_init_pio(dev, EVO_CURS(i))))
1536 goto error;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001537 }
1538
Ben Skeggsefd272a2011-07-05 11:58:58 +10001539 push = evo_wait(dev, 0, 32);
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001540 if (!push) {
1541 ret = -EBUSY;
1542 goto error;
1543 }
Ben Skeggsefd272a2011-07-05 11:58:58 +10001544 evo_mthd(push, 0x0088, 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001545 evo_data(push, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001546 evo_mthd(push, 0x0084, 1);
1547 evo_data(push, 0x00000000);
1548 evo_mthd(push, 0x0084, 1);
1549 evo_data(push, 0x80000000);
1550 evo_mthd(push, 0x008c, 1);
1551 evo_data(push, 0x00000000);
1552 evo_kick(push, dev, 0);
1553
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001554error:
1555 if (ret)
1556 nvd0_display_fini(dev);
1557 return ret;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001558}
1559
1560void
1561nvd0_display_destroy(struct drm_device *dev)
1562{
1563 struct drm_nouveau_private *dev_priv = dev->dev_private;
1564 struct nvd0_display *disp = nvd0_display(dev);
Ben Skeggs51beb422011-07-05 10:33:08 +10001565 struct pci_dev *pdev = dev->pdev;
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001566 int i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001567
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001568 for (i = 0; i < 3; i++) {
1569 pci_free_consistent(pdev, PAGE_SIZE, disp->evo[i].ptr,
1570 disp->evo[i].handle);
1571 }
1572
Ben Skeggs26f6d882011-07-04 16:25:18 +10001573 nouveau_gpuobj_ref(NULL, &disp->mem);
Ben Skeggs46005222011-07-05 11:01:13 +10001574 nouveau_irq_unregister(dev, 26);
Ben Skeggs51beb422011-07-05 10:33:08 +10001575
1576 dev_priv->engine.display.priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001577 kfree(disp);
1578}
1579
1580int
1581nvd0_display_create(struct drm_device *dev)
1582{
1583 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsefd272a2011-07-05 11:58:58 +10001584 struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001585 struct dcb_table *dcb = &dev_priv->vbios.dcb;
1586 struct drm_connector *connector, *tmp;
Ben Skeggs51beb422011-07-05 10:33:08 +10001587 struct pci_dev *pdev = dev->pdev;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001588 struct nvd0_display *disp;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001589 struct dcb_entry *dcbe;
1590 int ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001591
1592 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
1593 if (!disp)
1594 return -ENOMEM;
1595 dev_priv->engine.display.priv = disp;
1596
Ben Skeggs438d99e2011-07-05 16:48:06 +10001597 /* create crtc objects to represent the hw heads */
1598 for (i = 0; i < 2; i++) {
1599 ret = nvd0_crtc_create(dev, i);
1600 if (ret)
1601 goto out;
1602 }
1603
Ben Skeggs83fc0832011-07-05 13:08:40 +10001604 /* create encoder/connector objects based on VBIOS DCB table */
1605 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
1606 connector = nouveau_connector_create(dev, dcbe->connector);
1607 if (IS_ERR(connector))
1608 continue;
1609
1610 if (dcbe->location != DCB_LOC_ON_CHIP) {
1611 NV_WARN(dev, "skipping off-chip encoder %d/%d\n",
1612 dcbe->type, ffs(dcbe->or) - 1);
1613 continue;
1614 }
1615
1616 switch (dcbe->type) {
1617 case OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001618 case OUTPUT_LVDS:
Ben Skeggs83fc0832011-07-05 13:08:40 +10001619 nvd0_sor_create(connector, dcbe);
1620 break;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001621 case OUTPUT_ANALOG:
1622 nvd0_dac_create(connector, dcbe);
1623 break;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001624 default:
1625 NV_WARN(dev, "skipping unsupported encoder %d/%d\n",
1626 dcbe->type, ffs(dcbe->or) - 1);
1627 continue;
1628 }
1629 }
1630
1631 /* cull any connectors we created that don't have an encoder */
1632 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
1633 if (connector->encoder_ids[0])
1634 continue;
1635
1636 NV_WARN(dev, "%s has no encoders, removing\n",
1637 drm_get_connector_name(connector));
1638 connector->funcs->destroy(connector);
1639 }
1640
Ben Skeggs46005222011-07-05 11:01:13 +10001641 /* setup interrupt handling */
Ben Skeggsf20ce962011-07-08 13:17:01 +10001642 tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev);
Ben Skeggs46005222011-07-05 11:01:13 +10001643 nouveau_irq_register(dev, 26, nvd0_display_intr);
1644
Ben Skeggs51beb422011-07-05 10:33:08 +10001645 /* hash table and dma objects for the memory areas we care about */
Ben Skeggsefd272a2011-07-05 11:58:58 +10001646 ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000,
1647 NVOBJ_FLAG_ZERO_ALLOC, &disp->mem);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001648 if (ret)
1649 goto out;
1650
Ben Skeggsefd272a2011-07-05 11:58:58 +10001651 nv_wo32(disp->mem, 0x1000, 0x00000049);
1652 nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8);
1653 nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8);
1654 nv_wo32(disp->mem, 0x100c, 0x00000000);
1655 nv_wo32(disp->mem, 0x1010, 0x00000000);
1656 nv_wo32(disp->mem, 0x1014, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001657 nv_wo32(disp->mem, 0x0000, NvEvoSync);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001658 nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001);
1659
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001660 nv_wo32(disp->mem, 0x1020, 0x00000049);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001661 nv_wo32(disp->mem, 0x1024, 0x00000000);
1662 nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8);
1663 nv_wo32(disp->mem, 0x102c, 0x00000000);
1664 nv_wo32(disp->mem, 0x1030, 0x00000000);
1665 nv_wo32(disp->mem, 0x1034, 0x00000000);
Ben Skeggs37b034a2011-07-08 14:43:19 +10001666 nv_wo32(disp->mem, 0x0008, NvEvoVRAM);
Ben Skeggsefd272a2011-07-05 11:58:58 +10001667 nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001);
1668
Ben Skeggsc0cc92a2011-07-06 11:40:45 +10001669 nv_wo32(disp->mem, 0x1040, 0x00000009);
1670 nv_wo32(disp->mem, 0x1044, 0x00000000);
1671 nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8);
1672 nv_wo32(disp->mem, 0x104c, 0x00000000);
1673 nv_wo32(disp->mem, 0x1050, 0x00000000);
1674 nv_wo32(disp->mem, 0x1054, 0x00000000);
1675 nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP);
1676 nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001);
1677
1678 nv_wo32(disp->mem, 0x1060, 0x0fe00009);
1679 nv_wo32(disp->mem, 0x1064, 0x00000000);
1680 nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8);
1681 nv_wo32(disp->mem, 0x106c, 0x00000000);
1682 nv_wo32(disp->mem, 0x1070, 0x00000000);
1683 nv_wo32(disp->mem, 0x1074, 0x00000000);
1684 nv_wo32(disp->mem, 0x0018, NvEvoFB32);
1685 nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001);
1686
Ben Skeggsefd272a2011-07-05 11:58:58 +10001687 pinstmem->flush(dev);
1688
Ben Skeggs51beb422011-07-05 10:33:08 +10001689 /* push buffers for evo channels */
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001690 for (i = 0; i < 3; i++) {
1691 disp->evo[i].ptr = pci_alloc_consistent(pdev, PAGE_SIZE,
1692 &disp->evo[i].handle);
1693 if (!disp->evo[i].ptr) {
1694 ret = -ENOMEM;
1695 goto out;
1696 }
Ben Skeggs51beb422011-07-05 10:33:08 +10001697 }
1698
Ben Skeggs26f6d882011-07-04 16:25:18 +10001699out:
1700 if (ret)
1701 nvd0_display_destroy(dev);
1702 return ret;
1703}