aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv50_crtc.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2009-12-11 04:24:15 -0500
committerDave Airlie <airlied@redhat.com>2009-12-11 06:29:34 -0500
commit6ee738610f41b59733f63718f0bdbcba7d3a3f12 (patch)
treeeccb9f07671998c50a1bc606a54cd6f82ba43e0a /drivers/gpu/drm/nouveau/nv50_crtc.c
parentd1ede145cea25c5b6d2ebb19b167af14e374bb45 (diff)
drm/nouveau: Add DRM driver for NVIDIA GPUs
This adds a drm/kms staging non-API stable driver for GPUs from NVIDIA. This driver is a KMS-based driver and requires a compatible nouveau userspace libdrm and nouveau X.org driver. This driver requires firmware files not available in this kernel tree, interested parties can find them via the nouveau project git archive. This driver is reverse engineered, and is in no way supported by nVidia. Support for nearly the complete range of nvidia hw from nv04->g80 (nv50) is available, and the kms driver should support driving nearly all output types (displayport is under development still) along with supporting suspend/resume. This work is all from the upstream nouveau project found at nouveau.freedesktop.org. The original authors list from nouveau git tree is: Anssi Hannula <anssi.hannula@iki.fi> Ben Skeggs <bskeggs@redhat.com> Francisco Jerez <currojerez@riseup.net> Maarten Maathuis <madman2003@gmail.com> Marcin Koƛcielnicki <koriakin@0x04.net> Matthew Garrett <mjg@redhat.com> Matt Parnell <mparnell@gmail.com> Patrice Mandin <patmandin@gmail.com> Pekka Paalanen <pq@iki.fi> Xavier Chantry <shiningxc@gmail.com> along with project founder Stephane Marchesin <marchesin@icps.u-strasbg.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_crtc.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c769
1 files changed, 769 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
new file mode 100644
index 000000000000..f8e28a1e44e7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -0,0 +1,769 @@
1/*
2 * Copyright (C) 2008 Maarten Maathuis.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27#include "drmP.h"
28#include "drm_mode.h"
29#include "drm_crtc_helper.h"
30
31#define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO)
32#include "nouveau_reg.h"
33#include "nouveau_drv.h"
34#include "nouveau_hw.h"
35#include "nouveau_encoder.h"
36#include "nouveau_crtc.h"
37#include "nouveau_fb.h"
38#include "nouveau_connector.h"
39#include "nv50_display.h"
40
41static void
42nv50_crtc_lut_load(struct drm_crtc *crtc)
43{
44 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
45 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
46 int i;
47
48 NV_DEBUG(crtc->dev, "\n");
49
50 for (i = 0; i < 256; i++) {
51 writew(nv_crtc->lut.r[i] >> 2, lut + 8*i + 0);
52 writew(nv_crtc->lut.g[i] >> 2, lut + 8*i + 2);
53 writew(nv_crtc->lut.b[i] >> 2, lut + 8*i + 4);
54 }
55
56 if (nv_crtc->lut.depth == 30) {
57 writew(nv_crtc->lut.r[i - 1] >> 2, lut + 8*i + 0);
58 writew(nv_crtc->lut.g[i - 1] >> 2, lut + 8*i + 2);
59 writew(nv_crtc->lut.b[i - 1] >> 2, lut + 8*i + 4);
60 }
61}
62
63int
64nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
65{
66 struct drm_device *dev = nv_crtc->base.dev;
67 struct drm_nouveau_private *dev_priv = dev->dev_private;
68 struct nouveau_channel *evo = dev_priv->evo;
69 int index = nv_crtc->index, ret;
70
71 NV_DEBUG(dev, "index %d\n", nv_crtc->index);
72 NV_DEBUG(dev, "%s\n", blanked ? "blanked" : "unblanked");
73
74 if (blanked) {
75 nv_crtc->cursor.hide(nv_crtc, false);
76
77 ret = RING_SPACE(evo, dev_priv->chipset != 0x50 ? 7 : 5);
78 if (ret) {
79 NV_ERROR(dev, "no space while blanking crtc\n");
80 return ret;
81 }
82 BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, CLUT_MODE), 2);
83 OUT_RING(evo, NV50_EVO_CRTC_CLUT_MODE_BLANK);
84 OUT_RING(evo, 0);
85 if (dev_priv->chipset != 0x50) {
86 BEGIN_RING(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
87 OUT_RING(evo, NV84_EVO_CRTC_CLUT_DMA_HANDLE_NONE);
88 }
89
90 BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1);
91 OUT_RING(evo, NV50_EVO_CRTC_FB_DMA_HANDLE_NONE);
92 } else {
93 if (nv_crtc->cursor.visible)
94 nv_crtc->cursor.show(nv_crtc, false);
95 else
96 nv_crtc->cursor.hide(nv_crtc, false);
97
98 ret = RING_SPACE(evo, dev_priv->chipset != 0x50 ? 10 : 8);
99 if (ret) {
100 NV_ERROR(dev, "no space while unblanking crtc\n");
101 return ret;
102 }
103 BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, CLUT_MODE), 2);
104 OUT_RING(evo, nv_crtc->lut.depth == 8 ?
105 NV50_EVO_CRTC_CLUT_MODE_OFF :
106 NV50_EVO_CRTC_CLUT_MODE_ON);
107 OUT_RING(evo, (nv_crtc->lut.nvbo->bo.mem.mm_node->start <<
108 PAGE_SHIFT) >> 8);
109 if (dev_priv->chipset != 0x50) {
110 BEGIN_RING(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
111 OUT_RING(evo, NvEvoVRAM);
112 }
113
114 BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, FB_OFFSET), 2);
115 OUT_RING(evo, nv_crtc->fb.offset >> 8);
116 OUT_RING(evo, 0);
117 BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1);
118 if (dev_priv->chipset != 0x50)
119 if (nv_crtc->fb.tile_flags == 0x7a00)
120 OUT_RING(evo, NvEvoFB32);
121 else
122 if (nv_crtc->fb.tile_flags == 0x7000)
123 OUT_RING(evo, NvEvoFB16);
124 else
125 OUT_RING(evo, NvEvoVRAM);
126 else
127 OUT_RING(evo, NvEvoVRAM);
128 }
129
130 nv_crtc->fb.blanked = blanked;
131 return 0;
132}
133
134static int
135nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update)
136{
137 struct drm_device *dev = nv_crtc->base.dev;
138 struct drm_nouveau_private *dev_priv = dev->dev_private;
139 struct nouveau_channel *evo = dev_priv->evo;
140 int ret;
141
142 NV_DEBUG(dev, "\n");
143
144 ret = RING_SPACE(evo, 2 + (update ? 2 : 0));
145 if (ret) {
146 NV_ERROR(dev, "no space while setting dither\n");
147 return ret;
148 }
149
150 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, DITHER_CTRL), 1);
151 if (on)
152 OUT_RING(evo, NV50_EVO_CRTC_DITHER_CTRL_ON);
153 else
154 OUT_RING(evo, NV50_EVO_CRTC_DITHER_CTRL_OFF);
155
156 if (update) {
157 BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
158 OUT_RING(evo, 0);
159 FIRE_RING(evo);
160 }
161
162 return 0;
163}
164
165struct nouveau_connector *
166nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
167{
168 struct drm_device *dev = nv_crtc->base.dev;
169 struct drm_connector *connector;
170 struct drm_crtc *crtc = to_drm_crtc(nv_crtc);
171
172 /* The safest approach is to find an encoder with the right crtc, that
173 * is also linked to a connector. */
174 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
175 if (connector->encoder)
176 if (connector->encoder->crtc == crtc)
177 return nouveau_connector(connector);
178 }
179
180 return NULL;
181}
182
183static int
184nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update)
185{
186 struct nouveau_connector *nv_connector =
187 nouveau_crtc_connector_get(nv_crtc);
188 struct drm_device *dev = nv_crtc->base.dev;
189 struct drm_nouveau_private *dev_priv = dev->dev_private;
190 struct nouveau_channel *evo = dev_priv->evo;
191 struct drm_display_mode *native_mode = NULL;
192 struct drm_display_mode *mode = &nv_crtc->base.mode;
193 uint32_t outX, outY, horiz, vert;
194 int ret;
195
196 NV_DEBUG(dev, "\n");
197
198 switch (scaling_mode) {
199 case DRM_MODE_SCALE_NONE:
200 break;
201 default:
202 if (!nv_connector || !nv_connector->native_mode) {
203 NV_ERROR(dev, "No native mode, forcing panel scaling\n");
204 scaling_mode = DRM_MODE_SCALE_NONE;
205 } else {
206 native_mode = nv_connector->native_mode;
207 }
208 break;
209 }
210
211 switch (scaling_mode) {
212 case DRM_MODE_SCALE_ASPECT:
213 horiz = (native_mode->hdisplay << 19) / mode->hdisplay;
214 vert = (native_mode->vdisplay << 19) / mode->vdisplay;
215
216 if (vert > horiz) {
217 outX = (mode->hdisplay * horiz) >> 19;
218 outY = (mode->vdisplay * horiz) >> 19;
219 } else {
220 outX = (mode->hdisplay * vert) >> 19;
221 outY = (mode->vdisplay * vert) >> 19;
222 }
223 break;
224 case DRM_MODE_SCALE_FULLSCREEN:
225 outX = native_mode->hdisplay;
226 outY = native_mode->vdisplay;
227 break;
228 case DRM_MODE_SCALE_CENTER:
229 case DRM_MODE_SCALE_NONE:
230 default:
231 outX = mode->hdisplay;
232 outY = mode->vdisplay;
233 break;
234 }
235
236 ret = RING_SPACE(evo, update ? 7 : 5);
237 if (ret)
238 return ret;
239
240 /* Got a better name for SCALER_ACTIVE? */
241 /* One day i've got to really figure out why this is needed. */
242 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_CTRL), 1);
243 if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) ||
244 (mode->flags & DRM_MODE_FLAG_INTERLACE) ||
245 mode->hdisplay != outX || mode->vdisplay != outY) {
246 OUT_RING(evo, NV50_EVO_CRTC_SCALE_CTRL_ACTIVE);
247 } else {
248 OUT_RING(evo, NV50_EVO_CRTC_SCALE_CTRL_INACTIVE);
249 }
250
251 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_RES1), 2);
252 OUT_RING(evo, outY << 16 | outX);
253 OUT_RING(evo, outY << 16 | outX);
254
255 if (update) {
256 BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
257 OUT_RING(evo, 0);
258 FIRE_RING(evo);
259 }
260
261 return 0;
262}
263
264int
265nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
266{
267 uint32_t pll_reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
268 struct nouveau_pll_vals pll;
269 struct pll_lims limits;
270 uint32_t reg1, reg2;
271 int ret;
272
273 ret = get_pll_limits(dev, pll_reg, &limits);
274 if (ret)
275 return ret;
276
277 ret = nouveau_calc_pll_mnp(dev, &limits, pclk, &pll);
278 if (ret <= 0)
279 return ret;
280
281 if (limits.vco2.maxfreq) {
282 reg1 = nv_rd32(dev, pll_reg + 4) & 0xff00ff00;
283 reg2 = nv_rd32(dev, pll_reg + 8) & 0x8000ff00;
284 nv_wr32(dev, pll_reg, 0x10000611);
285 nv_wr32(dev, pll_reg + 4, reg1 | (pll.M1 << 16) | pll.N1);
286 nv_wr32(dev, pll_reg + 8,
287 reg2 | (pll.log2P << 28) | (pll.M2 << 16) | pll.N2);
288 } else {
289 reg1 = nv_rd32(dev, pll_reg + 4) & 0xffc00000;
290 nv_wr32(dev, pll_reg, 0x50000610);
291 nv_wr32(dev, pll_reg + 4, reg1 |
292 (pll.log2P << 16) | (pll.M1 << 8) | pll.N1);
293 }
294
295 return 0;
296}
297
298static void
299nv50_crtc_destroy(struct drm_crtc *crtc)
300{
301 struct drm_device *dev = crtc->dev;
302 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
303
304 NV_DEBUG(dev, "\n");
305
306 if (!crtc)
307 return;
308
309 drm_crtc_cleanup(&nv_crtc->base);
310
311 nv50_cursor_fini(nv_crtc);
312
313 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
314 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
315 kfree(nv_crtc->mode);
316 kfree(nv_crtc);
317}
318
319int
320nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
321 uint32_t buffer_handle, uint32_t width, uint32_t height)
322{
323 struct drm_device *dev = crtc->dev;
324 struct drm_nouveau_private *dev_priv = dev->dev_private;
325 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
326 struct nouveau_bo *cursor = NULL;
327 struct drm_gem_object *gem;
328 int ret = 0, i;
329
330 if (width != 64 || height != 64)
331 return -EINVAL;
332
333 if (!buffer_handle) {
334 nv_crtc->cursor.hide(nv_crtc, true);
335 return 0;
336 }
337
338 gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
339 if (!gem)
340 return -EINVAL;
341 cursor = nouveau_gem_object(gem);
342
343 ret = nouveau_bo_map(cursor);
344 if (ret)
345 goto out;
346
347 /* The simple will do for now. */
348 for (i = 0; i < 64 * 64; i++)
349 nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, nouveau_bo_rd32(cursor, i));
350
351 nouveau_bo_unmap(cursor);
352
353 nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset -
354 dev_priv->vm_vram_base);
355 nv_crtc->cursor.show(nv_crtc, true);
356
357out:
358 mutex_lock(&dev->struct_mutex);
359 drm_gem_object_unreference(gem);
360 mutex_unlock(&dev->struct_mutex);
361 return ret;
362}
363
364int
365nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
366{
367 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
368
369 nv_crtc->cursor.set_pos(nv_crtc, x, y);
370 return 0;
371}
372
373static void
374nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
375 uint32_t size)
376{
377 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
378 int i;
379
380 if (size != 256)
381 return;
382
383 for (i = 0; i < 256; i++) {
384 nv_crtc->lut.r[i] = r[i];
385 nv_crtc->lut.g[i] = g[i];
386 nv_crtc->lut.b[i] = b[i];
387 }
388
389 /* We need to know the depth before we upload, but it's possible to
390 * get called before a framebuffer is bound. If this is the case,
391 * mark the lut values as dirty by setting depth==0, and it'll be
392 * uploaded on the first mode_set_base()
393 */
394 if (!nv_crtc->base.fb) {
395 nv_crtc->lut.depth = 0;
396 return;
397 }
398
399 nv50_crtc_lut_load(crtc);
400}
401
402static void
403nv50_crtc_save(struct drm_crtc *crtc)
404{
405 NV_ERROR(crtc->dev, "!!\n");
406}
407
408static void
409nv50_crtc_restore(struct drm_crtc *crtc)
410{
411 NV_ERROR(crtc->dev, "!!\n");
412}
413
414static const struct drm_crtc_funcs nv50_crtc_funcs = {
415 .save = nv50_crtc_save,
416 .restore = nv50_crtc_restore,
417 .cursor_set = nv50_crtc_cursor_set,
418 .cursor_move = nv50_crtc_cursor_move,
419 .gamma_set = nv50_crtc_gamma_set,
420 .set_config = drm_crtc_helper_set_config,
421 .destroy = nv50_crtc_destroy,
422};
423
424static void
425nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
426{
427}
428
429static void
430nv50_crtc_prepare(struct drm_crtc *crtc)
431{
432 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
433 struct drm_device *dev = crtc->dev;
434 struct drm_encoder *encoder;
435
436 NV_DEBUG(dev, "index %d\n", nv_crtc->index);
437
438 /* Disconnect all unused encoders. */
439 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
440 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
441
442 if (drm_helper_encoder_in_use(encoder))
443 continue;
444
445 nv_encoder->disconnect(nv_encoder);
446 }
447
448 nv50_crtc_blank(nv_crtc, true);
449}
450
451static void
452nv50_crtc_commit(struct drm_crtc *crtc)
453{
454 struct drm_crtc *crtc2;
455 struct drm_device *dev = crtc->dev;
456 struct drm_nouveau_private *dev_priv = dev->dev_private;
457 struct nouveau_channel *evo = dev_priv->evo;
458 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
459 int ret;
460
461 NV_DEBUG(dev, "index %d\n", nv_crtc->index);
462
463 nv50_crtc_blank(nv_crtc, false);
464
465 /* Explicitly blank all unused crtc's. */
466 list_for_each_entry(crtc2, &dev->mode_config.crtc_list, head) {
467 if (!drm_helper_crtc_in_use(crtc2))
468 nv50_crtc_blank(nouveau_crtc(crtc2), true);
469 }
470
471 ret = RING_SPACE(evo, 2);
472 if (ret) {
473 NV_ERROR(dev, "no space while committing crtc\n");
474 return;
475 }
476 BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
477 OUT_RING(evo, 0);
478 FIRE_RING(evo);
479}
480
481static bool
482nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
483 struct drm_display_mode *adjusted_mode)
484{
485 return true;
486}
487
488static int
489nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
490 struct drm_framebuffer *old_fb, bool update)
491{
492 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
493 struct drm_device *dev = nv_crtc->base.dev;
494 struct drm_nouveau_private *dev_priv = dev->dev_private;
495 struct nouveau_channel *evo = dev_priv->evo;
496 struct drm_framebuffer *drm_fb = nv_crtc->base.fb;
497 struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
498 int ret, format;
499
500 NV_DEBUG(dev, "index %d\n", nv_crtc->index);
501
502 switch (drm_fb->depth) {
503 case 8:
504 format = NV50_EVO_CRTC_FB_DEPTH_8;
505 break;
506 case 15:
507 format = NV50_EVO_CRTC_FB_DEPTH_15;
508 break;
509 case 16:
510 format = NV50_EVO_CRTC_FB_DEPTH_16;
511 break;
512 case 24:
513 case 32:
514 format = NV50_EVO_CRTC_FB_DEPTH_24;
515 break;
516 case 30:
517 format = NV50_EVO_CRTC_FB_DEPTH_30;
518 break;
519 default:
520 NV_ERROR(dev, "unknown depth %d\n", drm_fb->depth);
521 return -EINVAL;
522 }
523
524 ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
525 if (ret)
526 return ret;
527
528 if (old_fb) {
529 struct nouveau_framebuffer *ofb = nouveau_framebuffer(old_fb);
530 nouveau_bo_unpin(ofb->nvbo);
531 }
532
533 nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base;
534 nv_crtc->fb.tile_flags = fb->nvbo->tile_flags;
535 nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
536 if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) {
537 ret = RING_SPACE(evo, 2);
538 if (ret)
539 return ret;
540
541 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_DMA), 1);
542 if (nv_crtc->fb.tile_flags == 0x7a00)
543 OUT_RING(evo, NvEvoFB32);
544 else
545 if (nv_crtc->fb.tile_flags == 0x7000)
546 OUT_RING(evo, NvEvoFB16);
547 else
548 OUT_RING(evo, NvEvoVRAM);
549 }
550
551 ret = RING_SPACE(evo, 12);
552 if (ret)
553 return ret;
554
555 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_OFFSET), 5);
556 OUT_RING(evo, nv_crtc->fb.offset >> 8);
557 OUT_RING(evo, 0);
558 OUT_RING(evo, (drm_fb->height << 16) | drm_fb->width);
559 if (!nv_crtc->fb.tile_flags) {
560 OUT_RING(evo, drm_fb->pitch | (1 << 20));
561 } else {
562 OUT_RING(evo, ((drm_fb->pitch / 4) << 4) |
563 fb->nvbo->tile_mode);
564 }
565 if (dev_priv->chipset == 0x50)
566 OUT_RING(evo, (fb->nvbo->tile_flags << 8) | format);
567 else
568 OUT_RING(evo, format);
569
570 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CLUT_MODE), 1);
571 OUT_RING(evo, fb->base.depth == 8 ?
572 NV50_EVO_CRTC_CLUT_MODE_OFF : NV50_EVO_CRTC_CLUT_MODE_ON);
573
574 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1);
575 OUT_RING(evo, NV50_EVO_CRTC_COLOR_CTRL_COLOR);
576 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_POS), 1);
577 OUT_RING(evo, (y << 16) | x);
578
579 if (nv_crtc->lut.depth != fb->base.depth) {
580 nv_crtc->lut.depth = fb->base.depth;
581 nv50_crtc_lut_load(crtc);
582 }
583
584 if (update) {
585 ret = RING_SPACE(evo, 2);
586 if (ret)
587 return ret;
588 BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
589 OUT_RING(evo, 0);
590 FIRE_RING(evo);
591 }
592
593 return 0;
594}
595
596static int
597nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
598 struct drm_display_mode *adjusted_mode, int x, int y,
599 struct drm_framebuffer *old_fb)
600{
601 struct drm_device *dev = crtc->dev;
602 struct drm_nouveau_private *dev_priv = dev->dev_private;
603 struct nouveau_channel *evo = dev_priv->evo;
604 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
605 struct nouveau_connector *nv_connector = NULL;
606 uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end;
607 uint32_t hunk1, vunk1, vunk2a, vunk2b;
608 int ret;
609
610 /* Find the connector attached to this CRTC */
611 nv_connector = nouveau_crtc_connector_get(nv_crtc);
612
613 *nv_crtc->mode = *adjusted_mode;
614
615 NV_DEBUG(dev, "index %d\n", nv_crtc->index);
616
617 hsync_dur = adjusted_mode->hsync_end - adjusted_mode->hsync_start;
618 vsync_dur = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
619 hsync_start_to_end = adjusted_mode->htotal - adjusted_mode->hsync_start;
620 vsync_start_to_end = adjusted_mode->vtotal - adjusted_mode->vsync_start;
621 /* I can't give this a proper name, anyone else can? */
622 hunk1 = adjusted_mode->htotal -
623 adjusted_mode->hsync_start + adjusted_mode->hdisplay;
624 vunk1 = adjusted_mode->vtotal -
625 adjusted_mode->vsync_start + adjusted_mode->vdisplay;
626 /* Another strange value, this time only for interlaced adjusted_modes. */
627 vunk2a = 2 * adjusted_mode->vtotal -
628 adjusted_mode->vsync_start + adjusted_mode->vdisplay;
629 vunk2b = adjusted_mode->vtotal -
630 adjusted_mode->vsync_start + adjusted_mode->vtotal;
631
632 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
633 vsync_dur /= 2;
634 vsync_start_to_end /= 2;
635 vunk1 /= 2;
636 vunk2a /= 2;
637 vunk2b /= 2;
638 /* magic */
639 if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) {
640 vsync_start_to_end -= 1;
641 vunk1 -= 1;
642 vunk2a -= 1;
643 vunk2b -= 1;
644 }
645 }
646
647 ret = RING_SPACE(evo, 17);
648 if (ret)
649 return ret;
650
651 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CLOCK), 2);
652 OUT_RING(evo, adjusted_mode->clock | 0x800000);
653 OUT_RING(evo, (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 0);
654
655 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, DISPLAY_START), 5);
656 OUT_RING(evo, 0);
657 OUT_RING(evo, (adjusted_mode->vtotal << 16) | adjusted_mode->htotal);
658 OUT_RING(evo, (vsync_dur - 1) << 16 | (hsync_dur - 1));
659 OUT_RING(evo, (vsync_start_to_end - 1) << 16 |
660 (hsync_start_to_end - 1));
661 OUT_RING(evo, (vunk1 - 1) << 16 | (hunk1 - 1));
662
663 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
664 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, UNK0824), 1);
665 OUT_RING(evo, (vunk2b - 1) << 16 | (vunk2a - 1));
666 } else {
667 OUT_RING(evo, 0);
668 OUT_RING(evo, 0);
669 }
670
671 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, UNK082C), 1);
672 OUT_RING(evo, 0);
673
674 /* This is the actual resolution of the mode. */
675 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, REAL_RES), 1);
676 OUT_RING(evo, (mode->vdisplay << 16) | mode->hdisplay);
677 BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_CENTER_OFFSET), 1);
678 OUT_RING(evo, NV50_EVO_CRTC_SCALE_CENTER_OFFSET_VAL(0, 0));
679
680 nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering, false);
681 nv_crtc->set_scale(nv_crtc, nv_connector->scaling_mode, false);
682
683 return nv50_crtc_do_mode_set_base(crtc, x, y, old_fb, false);
684}
685
686static int
687nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
688 struct drm_framebuffer *old_fb)
689{
690 return nv50_crtc_do_mode_set_base(crtc, x, y, old_fb, true);
691}
692
693static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = {
694 .dpms = nv50_crtc_dpms,
695 .prepare = nv50_crtc_prepare,
696 .commit = nv50_crtc_commit,
697 .mode_fixup = nv50_crtc_mode_fixup,
698 .mode_set = nv50_crtc_mode_set,
699 .mode_set_base = nv50_crtc_mode_set_base,
700 .load_lut = nv50_crtc_lut_load,
701};
702
703int
704nv50_crtc_create(struct drm_device *dev, int index)
705{
706 struct nouveau_crtc *nv_crtc = NULL;
707 int ret, i;
708
709 NV_DEBUG(dev, "\n");
710
711 nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
712 if (!nv_crtc)
713 return -ENOMEM;
714
715 nv_crtc->mode = kzalloc(sizeof(*nv_crtc->mode), GFP_KERNEL);
716 if (!nv_crtc->mode) {
717 kfree(nv_crtc);
718 return -ENOMEM;
719 }
720
721 /* Default CLUT parameters, will be activated on the hw upon
722 * first mode set.
723 */
724 for (i = 0; i < 256; i++) {
725 nv_crtc->lut.r[i] = i << 8;
726 nv_crtc->lut.g[i] = i << 8;
727 nv_crtc->lut.b[i] = i << 8;
728 }
729 nv_crtc->lut.depth = 0;
730
731 ret = nouveau_bo_new(dev, NULL, 4096, 0x100, TTM_PL_FLAG_VRAM,
732 0, 0x0000, false, true, &nv_crtc->lut.nvbo);
733 if (!ret) {
734 ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
735 if (!ret)
736 ret = nouveau_bo_map(nv_crtc->lut.nvbo);
737 if (ret)
738 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
739 }
740
741 if (ret) {
742 kfree(nv_crtc->mode);
743 kfree(nv_crtc);
744 return ret;
745 }
746
747 nv_crtc->index = index;
748
749 /* set function pointers */
750 nv_crtc->set_dither = nv50_crtc_set_dither;
751 nv_crtc->set_scale = nv50_crtc_set_scale;
752
753 drm_crtc_init(dev, &nv_crtc->base, &nv50_crtc_funcs);
754 drm_crtc_helper_add(&nv_crtc->base, &nv50_crtc_helper_funcs);
755 drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
756
757 ret = nouveau_bo_new(dev, NULL, 64*64*4, 0x100, TTM_PL_FLAG_VRAM,
758 0, 0x0000, false, true, &nv_crtc->cursor.nvbo);
759 if (!ret) {
760 ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
761 if (!ret)
762 ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
763 if (ret)
764 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
765 }
766
767 nv50_cursor_init(nv_crtc);
768 return 0;
769}