Commit 616a5f57 authored by Ben Skeggs's avatar Ben Skeggs

drm/nv50/disp: rewrite crtc timing calculation, with proper names and fixes

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent a03a8623
...@@ -588,89 +588,74 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, ...@@ -588,89 +588,74 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
} }
static int static int
nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
struct drm_display_mode *adjusted_mode, int x, int y, struct drm_display_mode *mode, int x, int y,
struct drm_framebuffer *old_fb) struct drm_framebuffer *old_fb)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct nouveau_channel *evo = nv50_display(dev)->master; struct nouveau_channel *evo = nv50_display(dev)->master;
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct nouveau_connector *nv_connector = NULL; u32 head = nv_crtc->index * 0x400;
uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end; u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
uint32_t hunk1, vunk1, vunk2a, vunk2b; u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
u32 vblan2e = 0, vblan2s = 1;
int ret; int ret;
/* Find the connector attached to this CRTC */ /* hw timing description looks like this:
nv_connector = nouveau_crtc_connector_get(nv_crtc); *
* <sync> <back porch> <---------display---------> <front porch>
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); * ______
* |____________|---------------------------|____________|
*
* ^ synce ^ blanke ^ blanks ^ active
*
* interlaced modes also have 2 additional values pointing at the end
* and start of the next field's blanking period.
*/
hsync_dur = adjusted_mode->hsync_end - adjusted_mode->hsync_start; hactive = mode->htotal;
vsync_dur = adjusted_mode->vsync_end - adjusted_mode->vsync_start; hsynce = mode->hsync_end - mode->hsync_start - 1;
hsync_start_to_end = adjusted_mode->htotal - adjusted_mode->hsync_start; hbackp = mode->htotal - mode->hsync_end;
vsync_start_to_end = adjusted_mode->vtotal - adjusted_mode->vsync_start; hblanke = hsynce + hbackp;
/* I can't give this a proper name, anyone else can? */ hfrontp = mode->hsync_start - mode->hdisplay;
hunk1 = adjusted_mode->htotal - hblanks = mode->htotal - hfrontp - 1;
adjusted_mode->hsync_start + adjusted_mode->hdisplay;
vunk1 = adjusted_mode->vtotal - vactive = mode->vtotal * vscan / ilace;
adjusted_mode->vsync_start + adjusted_mode->vdisplay; vsynce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
/* Another strange value, this time only for interlaced adjusted_modes. */ vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
vunk2a = 2 * adjusted_mode->vtotal - vblanke = vsynce + vbackp;
adjusted_mode->vsync_start + adjusted_mode->vdisplay; vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
vunk2b = adjusted_mode->vtotal - vblanks = vactive - vfrontp - 1;
adjusted_mode->vsync_start + adjusted_mode->vtotal; if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
vblan2e = vactive + vsynce + vbackp;
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
vsync_dur /= 2; vactive = (vactive * 2) + 1;
vsync_start_to_end /= 2;
vunk1 /= 2;
vunk2a /= 2;
vunk2b /= 2;
/* magic */
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) {
vsync_start_to_end -= 1;
vunk1 -= 1;
vunk2a -= 1;
vunk2b -= 1;
}
} }
ret = RING_SPACE(evo, 19); ret = RING_SPACE(evo, 18);
if (ret) if (ret == 0) {
return ret; BEGIN_RING(evo, 0, 0x0804 + head, 2);
OUT_RING (evo, 0x00800000 | mode->clock);
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CLOCK), 2); OUT_RING (evo, (ilace == 2) ? 2 : 0);
OUT_RING(evo, adjusted_mode->clock | 0x800000); BEGIN_RING(evo, 0, 0x0810 + head, 6);
OUT_RING(evo, (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 0); OUT_RING (evo, 0x00000000); /* border colour */
OUT_RING (evo, (vactive << 16) | hactive);
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, DISPLAY_START), 5); OUT_RING (evo, ( vsynce << 16) | hsynce);
OUT_RING(evo, 0); OUT_RING (evo, (vblanke << 16) | hblanke);
OUT_RING(evo, (adjusted_mode->vtotal << 16) | adjusted_mode->htotal); OUT_RING (evo, (vblanks << 16) | hblanks);
OUT_RING(evo, (vsync_dur - 1) << 16 | (hsync_dur - 1)); OUT_RING (evo, (vblan2e << 16) | vblan2s);
OUT_RING(evo, (vsync_start_to_end - 1) << 16 | BEGIN_RING(evo, 0, 0x082c + head, 1);
(hsync_start_to_end - 1)); OUT_RING (evo, 0x00000000);
OUT_RING(evo, (vunk1 - 1) << 16 | (hunk1 - 1)); BEGIN_RING(evo, 0, 0x0900 + head, 1);
OUT_RING (evo, 0x00000311); /* makes sync channel work */
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { BEGIN_RING(evo, 0, 0x08c8 + head, 1);
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, UNK0824), 1); OUT_RING (evo, (umode->vdisplay << 16) | umode->hdisplay);
OUT_RING(evo, (vunk2b - 1) << 16 | (vunk2a - 1)); BEGIN_RING(evo, 0, 0x08d4 + head, 1);
} else { OUT_RING (evo, 0x00000000); /* screen position */
OUT_RING(evo, 0);
OUT_RING(evo, 0);
} }
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, UNK082C), 1);
OUT_RING (evo, 0);
/* required to make display sync channel not hate life */
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, UNK900), 1);
OUT_RING (evo, 0x00000311);
/* This is the actual resolution of the mode. */
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, REAL_RES), 1);
OUT_RING(evo, (mode->vdisplay << 16) | mode->hdisplay);
BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_CENTER_OFFSET), 1);
OUT_RING(evo, NV50_EVO_CRTC_SCALE_CENTER_OFFSET_VAL(0, 0));
nv_crtc->set_dither(nv_crtc, false); nv_crtc->set_dither(nv_crtc, false);
nv_crtc->set_scale(nv_crtc, false); nv_crtc->set_scale(nv_crtc, false);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment