diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-07-05 02:48:06 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-09-20 02:06:30 -0400 |
commit | 438d99e3b1752074af6d2d763a38906549048067 (patch) | |
tree | 878b8b41560d2d12b48a1ca34db8dc58db525202 /drivers/gpu/drm/nouveau/nvd0_display.c | |
parent | 270a5747802d4cf43b91b9e03cccb1fb5d5e8a34 (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.c | 457 |
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 | *****************************************************************************/ | ||
107 | static int | ||
108 | nvd0_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 | |||
139 | static int | ||
140 | nvd0_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 | |||
170 | static int | ||
171 | nvd0_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 | |||
195 | static void | ||
196 | nvd0_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 | |||
223 | static void | ||
224 | nvd0_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
225 | { | ||
226 | } | ||
227 | |||
228 | static void | ||
229 | nvd0_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 | |||
248 | static void | ||
249 | nvd0_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 | |||
271 | static bool | ||
272 | nvd0_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 | |||
278 | static int | ||
279 | nvd0_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 | |||
296 | static int | ||
297 | nvd0_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 | |||
350 | static int | ||
351 | nvd0_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 | |||
365 | static int | ||
366 | nvd0_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 | |||
375 | static void | ||
376 | nvd0_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 | |||
389 | static int | ||
390 | nvd0_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 | |||
429 | static int | ||
430 | nvd0_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 | |||
440 | static void | ||
441 | nvd0_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 | |||
457 | static void | ||
458 | nvd0_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 | |||
469 | static 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 | |||
480 | static 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 | |||
488 | static int | ||
489 | nvd0_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 | |||
541 | out: | ||
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); |