aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvd0_display.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-07-05 02:48:06 -0400
committerBen Skeggs <bskeggs@redhat.com>2011-09-20 02:06:30 -0400
commit438d99e3b1752074af6d2d763a38906549048067 (patch)
tree878b8b41560d2d12b48a1ca34db8dc58db525202 /drivers/gpu/drm/nouveau/nvd0_display.c
parent270a5747802d4cf43b91b9e03cccb1fb5d5e8a34 (diff)
drm/nvd0/disp: initial crtc object implementation
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvd0_display.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvd0_display.c457
1 files changed, 456 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index 65e48f953d4c..cf294886a696 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -31,6 +31,7 @@
31#include "nouveau_connector.h" 31#include "nouveau_connector.h"
32#include "nouveau_encoder.h" 32#include "nouveau_encoder.h"
33#include "nouveau_crtc.h" 33#include "nouveau_crtc.h"
34#include "nouveau_fb.h"
34 35
35#define MEM_SYNC 0xe0000001 36#define MEM_SYNC 0xe0000001
36#define MEM_VRAM 0xe0010000 37#define MEM_VRAM 0xe0010000
@@ -101,6 +102,449 @@ nvd0_display_crtc_get(struct drm_encoder *encoder)
101} 102}
102 103
103/****************************************************************************** 104/******************************************************************************
105 * CRTC
106 *****************************************************************************/
107static int
108nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update)
109{
110 struct drm_device *dev = nv_crtc->base.dev;
111 u32 *push, mode;
112
113 mode = 0x00000000;
114 if (on) {
115 /* 0x11: 6bpc dynamic 2x2
116 * 0x13: 8bpc dynamic 2x2
117 * 0x19: 6bpc static 2x2
118 * 0x1b: 8bpc static 2x2
119 * 0x21: 6bpc temporal
120 * 0x23: 8bpc temporal
121 */
122 mode = 0x00000011;
123 }
124
125 push = evo_wait(dev, 0, 4);
126 if (push) {
127 evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1);
128 evo_data(push, mode);
129 if (update) {
130 evo_mthd(push, 0x0080, 1);
131 evo_data(push, 0x00000000);
132 }
133 evo_kick(push, dev, 0);
134 }
135
136 return 0;
137}
138
139static int
140nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, int type, bool update)
141{
142 struct drm_display_mode *mode = &nv_crtc->base.mode;
143 struct drm_device *dev = nv_crtc->base.dev;
144 u32 *push;
145
146 /*XXX: actually handle scaling */
147
148 push = evo_wait(dev, 0, 16);
149 if (push) {
150 evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
151 evo_data(push, (mode->vdisplay << 16) | mode->hdisplay);
152 evo_data(push, (mode->vdisplay << 16) | mode->hdisplay);
153 evo_data(push, (mode->vdisplay << 16) | mode->hdisplay);
154 evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
155 evo_data(push, 0x00000000);
156 evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1);
157 evo_data(push, 0x00000000);
158 evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
159 evo_data(push, (mode->vdisplay << 16) | mode->hdisplay);
160 if (update) {
161 evo_mthd(push, 0x0080, 1);
162 evo_data(push, 0x00000000);
163 }
164 evo_kick(push, dev, 0);
165 }
166
167 return 0;
168}
169
170static int
171nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
172 int x, int y, bool update)
173{
174 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
175 u32 *push;
176
177 /*XXX*/
178 nv_crtc->fb.tile_flags = MEM_VRAM;
179
180 push = evo_wait(fb->dev, 0, 16);
181 if (push) {
182 evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1);
183 evo_data(push, nvfb->nvbo->bo.offset >> 8);
184 evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4);
185 evo_data(push, (fb->height << 16) | fb->width);
186 evo_data(push, nvfb->r_pitch);
187 evo_data(push, nvfb->r_format);
188 evo_data(push, nv_crtc->fb.tile_flags);
189 evo_kick(push, fb->dev, 0);
190 }
191
192 return 0;
193}
194
195static void
196nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update)
197{
198 struct drm_device *dev = nv_crtc->base.dev;
199 u32 *push = evo_wait(dev, 0, 16);
200 if (push) {
201 if (show) {
202 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
203 evo_data(push, 0x85000000);
204 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
205 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
206 evo_data(push, MEM_VRAM);
207 } else {
208 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1);
209 evo_data(push, 0x05000000);
210 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
211 evo_data(push, 0x00000000);
212 }
213
214 if (update) {
215 evo_mthd(push, 0x0080, 1);
216 evo_data(push, 0x00000000);
217 }
218
219 evo_kick(push, dev, 0);
220 }
221}
222
223static void
224nvd0_crtc_dpms(struct drm_crtc *crtc, int mode)
225{
226}
227
228static void
229nvd0_crtc_prepare(struct drm_crtc *crtc)
230{
231 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
232 u32 *push;
233
234 push = evo_wait(crtc->dev, 0, 2);
235 if (push) {
236 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
237 evo_data(push, 0x00000000);
238 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1);
239 evo_data(push, 0x03000000);
240 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
241 evo_data(push, 0x00000000);
242 evo_kick(push, crtc->dev, 0);
243 }
244
245 nvd0_crtc_cursor_show(nv_crtc, false, false);
246}
247
248static void
249nvd0_crtc_commit(struct drm_crtc *crtc)
250{
251 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
252 u32 *push;
253
254 push = evo_wait(crtc->dev, 0, 32);
255 if (push) {
256 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
257 evo_data(push, nv_crtc->fb.tile_flags);
258 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4);
259 evo_data(push, 0x83000000);
260 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
261 evo_data(push, 0x00000000);
262 evo_data(push, 0x00000000);
263 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
264 evo_data(push, MEM_VRAM);
265 evo_kick(push, crtc->dev, 0);
266 }
267
268 nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true);
269}
270
271static bool
272nvd0_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
273 struct drm_display_mode *adjusted_mode)
274{
275 return true;
276}
277
278static int
279nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
280{
281 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
282 int ret;
283
284 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
285 if (ret)
286 return ret;
287
288 if (old_fb) {
289 nvfb = nouveau_framebuffer(old_fb);
290 nouveau_bo_unpin(nvfb->nvbo);
291 }
292
293 return 0;
294}
295
296static int
297nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
298 struct drm_display_mode *mode, int x, int y,
299 struct drm_framebuffer *old_fb)
300{
301 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
302 struct nouveau_connector *nv_connector;
303 u32 htotal = mode->htotal;
304 u32 vtotal = mode->vtotal;
305 u32 hsyncw = mode->hsync_end - mode->hsync_start - 1;
306 u32 vsyncw = mode->vsync_end - mode->vsync_start - 1;
307 u32 hfrntp = mode->hsync_start - mode->hdisplay;
308 u32 vfrntp = mode->vsync_start - mode->vdisplay;
309 u32 hbackp = mode->htotal - mode->hsync_end;
310 u32 vbackp = mode->vtotal - mode->vsync_end;
311 u32 hss2be = hsyncw + hbackp;
312 u32 vss2be = vsyncw + vbackp;
313 u32 hss2de = htotal - hfrntp;
314 u32 vss2de = vtotal - vfrntp;
315 u32 hstart = 0;
316 u32 vstart = 0;
317 u32 *push;
318 int ret;
319
320 ret = nvd0_crtc_swap_fbs(crtc, old_fb);
321 if (ret)
322 return ret;
323
324 push = evo_wait(crtc->dev, 0, 64);
325 if (push) {
326 evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 5);
327 evo_data(push, (vstart << 16) | hstart);
328 evo_data(push, (vtotal << 16) | htotal);
329 evo_data(push, (vsyncw << 16) | hsyncw);
330 evo_data(push, (vss2be << 16) | hss2be);
331 evo_data(push, (vss2de << 16) | hss2de);
332 evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1);
333 evo_data(push, 0x00000000); /* ??? */
334 evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3);
335 evo_data(push, mode->clock * 1000);
336 evo_data(push, 0x00200000); /* ??? */
337 evo_data(push, mode->clock * 1000);
338 evo_mthd(push, 0x0408 + (nv_crtc->index * 0x300), 1);
339 evo_data(push, 0x31ec6000); /* ??? */
340 evo_kick(push, crtc->dev, 0);
341 }
342
343 nv_connector = nouveau_crtc_connector_get(nv_crtc);
344 nvd0_crtc_set_dither(nv_crtc, nv_connector->use_dithering, false);
345 nvd0_crtc_set_scale(nv_crtc, nv_connector->scaling_mode, false);
346 nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
347 return 0;
348}
349
350static int
351nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
352 struct drm_framebuffer *old_fb)
353{
354 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
355 int ret;
356
357 ret = nvd0_crtc_swap_fbs(crtc, old_fb);
358 if (ret)
359 return ret;
360
361 nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
362 return 0;
363}
364
365static int
366nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
367 struct drm_framebuffer *fb, int x, int y,
368 enum mode_set_atomic state)
369{
370 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
371 nvd0_crtc_set_image(nv_crtc, fb, x, y, true);
372 return 0;
373}
374
375static void
376nvd0_crtc_lut_load(struct drm_crtc *crtc)
377{
378 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
379 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
380 int i;
381
382 for (i = 0; i < 256; i++) {
383 writew(nv_crtc->lut.r[i] >> 2, lut + 8*i + 0);
384 writew(nv_crtc->lut.g[i] >> 2, lut + 8*i + 2);
385 writew(nv_crtc->lut.b[i] >> 2, lut + 8*i + 4);
386 }
387}
388
389static int
390nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
391 uint32_t handle, uint32_t width, uint32_t height)
392{
393 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
394 struct drm_device *dev = crtc->dev;
395 struct drm_gem_object *gem;
396 struct nouveau_bo *nvbo;
397 bool visible = (handle != 0);
398 int i, ret = 0;
399
400 if (visible) {
401 if (width != 64 || height != 64)
402 return -EINVAL;
403
404 gem = drm_gem_object_lookup(dev, file_priv, handle);
405 if (unlikely(!gem))
406 return -ENOENT;
407 nvbo = nouveau_gem_object(gem);
408
409 ret = nouveau_bo_map(nvbo);
410 if (ret == 0) {
411 for (i = 0; i < 64 * 64; i++) {
412 u32 v = nouveau_bo_rd32(nvbo, i);
413 nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v);
414 }
415 nouveau_bo_unmap(nvbo);
416 }
417
418 drm_gem_object_unreference_unlocked(gem);
419 }
420
421 if (visible != nv_crtc->cursor.visible) {
422 nvd0_crtc_cursor_show(nv_crtc, visible, true);
423 nv_crtc->cursor.visible = visible;
424 }
425
426 return ret;
427}
428
429static int
430nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
431{
432 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
433 const u32 data = (y << 16) | x;
434
435 nv_wr32(crtc->dev, 0x64d084 + (nv_crtc->index * 0x1000), data);
436 nv_wr32(crtc->dev, 0x64d080 + (nv_crtc->index * 0x1000), 0x00000000);
437 return 0;
438}
439
440static void
441nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
442 uint32_t start, uint32_t size)
443{
444 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
445 u32 end = max(start + size, (u32)256);
446 u32 i;
447
448 for (i = start; i < end; i++) {
449 nv_crtc->lut.r[i] = r[i];
450 nv_crtc->lut.g[i] = g[i];
451 nv_crtc->lut.b[i] = b[i];
452 }
453
454 nvd0_crtc_lut_load(crtc);
455}
456
457static void
458nvd0_crtc_destroy(struct drm_crtc *crtc)
459{
460 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
461 nouveau_bo_unmap(nv_crtc->cursor.nvbo);
462 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
463 nouveau_bo_unmap(nv_crtc->lut.nvbo);
464 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
465 drm_crtc_cleanup(crtc);
466 kfree(crtc);
467}
468
469static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = {
470 .dpms = nvd0_crtc_dpms,
471 .prepare = nvd0_crtc_prepare,
472 .commit = nvd0_crtc_commit,
473 .mode_fixup = nvd0_crtc_mode_fixup,
474 .mode_set = nvd0_crtc_mode_set,
475 .mode_set_base = nvd0_crtc_mode_set_base,
476 .mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic,
477 .load_lut = nvd0_crtc_lut_load,
478};
479
480static const struct drm_crtc_funcs nvd0_crtc_func = {
481 .cursor_set = nvd0_crtc_cursor_set,
482 .cursor_move = nvd0_crtc_cursor_move,
483 .gamma_set = nvd0_crtc_gamma_set,
484 .set_config = drm_crtc_helper_set_config,
485 .destroy = nvd0_crtc_destroy,
486};
487
488static int
489nvd0_crtc_create(struct drm_device *dev, int index)
490{
491 struct nouveau_crtc *nv_crtc;
492 struct drm_crtc *crtc;
493 int ret, i;
494
495 nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
496 if (!nv_crtc)
497 return -ENOMEM;
498
499 nv_crtc->index = index;
500 nv_crtc->set_dither = nvd0_crtc_set_dither;
501 nv_crtc->set_scale = nvd0_crtc_set_scale;
502 for (i = 0; i < 256; i++) {
503 nv_crtc->lut.r[i] = i << 8;
504 nv_crtc->lut.g[i] = i << 8;
505 nv_crtc->lut.b[i] = i << 8;
506 }
507
508 crtc = &nv_crtc->base;
509 drm_crtc_init(dev, crtc, &nvd0_crtc_func);
510 drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc);
511 drm_mode_crtc_set_gamma_size(crtc, 256);
512
513 ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
514 0, 0x0000, &nv_crtc->cursor.nvbo);
515 if (!ret) {
516 ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
517 if (!ret)
518 ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
519 if (ret)
520 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
521 }
522
523 if (ret)
524 goto out;
525
526 ret = nouveau_bo_new(dev, 4096, 0x100, TTM_PL_FLAG_VRAM,
527 0, 0x0000, &nv_crtc->lut.nvbo);
528 if (!ret) {
529 ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
530 if (!ret)
531 ret = nouveau_bo_map(nv_crtc->lut.nvbo);
532 if (ret)
533 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
534 }
535
536 if (ret)
537 goto out;
538
539 nvd0_crtc_lut_load(crtc);
540
541out:
542 if (ret)
543 nvd0_crtc_destroy(crtc);
544 return ret;
545}
546
547/******************************************************************************
104 * DAC 548 * DAC
105 *****************************************************************************/ 549 *****************************************************************************/
106 550
@@ -194,6 +638,7 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
194 if (push) { 638 if (push) {
195 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1); 639 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
196 evo_data(push, mode_ctrl); 640 evo_data(push, mode_ctrl);
641 evo_kick(push, encoder->dev, 0);
197 } 642 }
198 643
199 nv_encoder->crtc = encoder->crtc; 644 nv_encoder->crtc = encoder->crtc;
@@ -204,9 +649,12 @@ nvd0_sor_disconnect(struct drm_encoder *encoder)
204{ 649{
205 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 650 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
206 struct drm_device *dev = encoder->dev; 651 struct drm_device *dev = encoder->dev;
652 u32 *push;
207 653
208 if (nv_encoder->crtc) { 654 if (nv_encoder->crtc) {
209 u32 *push = evo_wait(dev, 0, 4); 655 nvd0_crtc_prepare(nv_encoder->crtc);
656
657 push = evo_wait(dev, 0, 4);
210 if (push) { 658 if (push) {
211 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1); 659 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
212 evo_data(push, 0x00000000); 660 evo_data(push, 0x00000000);
@@ -493,6 +941,13 @@ nvd0_display_create(struct drm_device *dev)
493 return -ENOMEM; 941 return -ENOMEM;
494 dev_priv->engine.display.priv = disp; 942 dev_priv->engine.display.priv = disp;
495 943
944 /* create crtc objects to represent the hw heads */
945 for (i = 0; i < 2; i++) {
946 ret = nvd0_crtc_create(dev, i);
947 if (ret)
948 goto out;
949 }
950
496 /* create encoder/connector objects based on VBIOS DCB table */ 951 /* create encoder/connector objects based on VBIOS DCB table */
497 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) { 952 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
498 connector = nouveau_connector_create(dev, dcbe->connector); 953 connector = nouveau_connector_create(dev, dcbe->connector);