summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nvd0_display.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-11-16 05:40:34 +0400
committerBen Skeggs <bskeggs@redhat.com>2012-11-29 03:57:55 +0400
commit419e8dc0afa4e0b2746f39dbef287f0c4befbbf2 (patch)
tree283d583eeed0773c47d6ab721a83d857a633ee76 /drivers/gpu/drm/nouveau/nvd0_display.c
parent97b19b5c6f32842c92800b62b367cc5a91555188 (diff)
downloadlinux-419e8dc0afa4e0b2746f39dbef287f0c4befbbf2.tar.xz
drm/nvd0/disp: implement sor support for older display classes
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.c106
1 files changed, 61 insertions, 45 deletions
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index 037602b72d6c..daf3e668212d 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -1529,26 +1529,33 @@ static void
nvd0_sor_disconnect(struct drm_encoder *encoder)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct drm_device *dev = encoder->dev;
+ struct nvd0_mast *mast = nvd0_mast(encoder->dev);
+ const int or = nv_encoder->or;
u32 *push;
if (nv_encoder->crtc) {
nvd0_crtc_prepare(nv_encoder->crtc);
- push = evo_wait(nvd0_mast(dev), 4);
+ push = evo_wait(mast, 4);
if (push) {
- evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
- evo_data(push, 0x00000000);
+ if (nvd0_vers(mast) < NVD0_DISP_MAST_CLASS) {
+ evo_mthd(push, 0x0600 + (or * 0x40), 1);
+ evo_data(push, 0x00000000);
+ } else {
+ evo_mthd(push, 0x0200 + (or * 0x20), 1);
+ evo_data(push, 0x00000000);
+ }
+
evo_mthd(push, 0x0080, 1);
evo_data(push, 0x00000000);
- evo_kick(push, nvd0_mast(dev));
+ evo_kick(push, mast);
}
nvd0_hdmi_disconnect(encoder);
-
- nv_encoder->crtc = NULL;
- nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
}
+
+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
+ nv_encoder->crtc = NULL;
}
static void
@@ -1569,84 +1576,76 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
struct drm_display_mode *mode)
{
struct nvd0_disp *disp = nvd0_disp(encoder->dev);
+ struct nvd0_mast *mast = nvd0_mast(encoder->dev);
struct drm_device *dev = encoder->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
struct nouveau_connector *nv_connector;
struct nvbios *bios = &drm->vbios;
- int or = nv_encoder->or;
- u32 mode_ctrl = (1 << nv_crtc->index);
- u32 syncs, magic, *push;
- u32 or_config;
-
- syncs = 0x00000001;
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- syncs |= 0x00000008;
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- syncs |= 0x00000010;
-
- magic = 0x31ec6000 | (nv_crtc->index << 25);
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- magic |= 0x00000001;
+ u32 *push, lvds = 0;
+ u8 owner = 1 << nv_crtc->index;
+ u8 proto = 0xf;
+ u8 depth = 0x0;
nv_connector = nouveau_encoder_connector_get(nv_encoder);
switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_TMDS:
if (nv_encoder->dcb->sorconf.link & 1) {
if (mode->clock < 165000)
- mode_ctrl |= 0x00000100;
+ proto = 0x1;
else
- mode_ctrl |= 0x00000500;
+ proto = 0x5;
} else {
- mode_ctrl |= 0x00000200;
+ proto = 0x2;
}
nvd0_hdmi_mode_set(encoder, mode);
break;
case DCB_OUTPUT_LVDS:
- or_config = (mode_ctrl & 0x00000f00) >> 8;
+ proto = 0x0;
+
if (bios->fp_no_ddc) {
if (bios->fp.dual_link)
- or_config |= 0x0100;
+ lvds |= 0x0100;
if (bios->fp.if_is_24bit)
- or_config |= 0x0200;
+ lvds |= 0x0200;
} else {
if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
if (((u8 *)nv_connector->edid)[121] == 2)
- or_config |= 0x0100;
+ lvds |= 0x0100;
} else
if (mode->clock >= bios->fp.duallink_transition_clk) {
- or_config |= 0x0100;
+ lvds |= 0x0100;
}
- if (or_config & 0x0100) {
+ if (lvds & 0x0100) {
if (bios->fp.strapless_is_24bit & 2)
- or_config |= 0x0200;
+ lvds |= 0x0200;
} else {
if (bios->fp.strapless_is_24bit & 1)
- or_config |= 0x0200;
+ lvds |= 0x0200;
}
if (nv_connector->base.display_info.bpc == 8)
- or_config |= 0x0200;
+ lvds |= 0x0200;
}
- nv_call(disp->core, NV50_DISP_SOR_LVDS_SCRIPT + or, or_config);
+ nv_call(disp->core, NV50_DISP_SOR_LVDS_SCRIPT + nv_encoder->or, lvds);
break;
case DCB_OUTPUT_DP:
if (nv_connector->base.display_info.bpc == 6) {
nv_encoder->dp.datarate = mode->clock * 18 / 8;
- syncs |= 0x00000002 << 6;
+ depth = 0x2;
} else {
nv_encoder->dp.datarate = mode->clock * 24 / 8;
- syncs |= 0x00000005 << 6;
+ depth = 0x5;
}
if (nv_encoder->dcb->sorconf.link & 1)
- mode_ctrl |= 0x00000800;
+ proto = 0x8;
else
- mode_ctrl |= 0x00000900;
+ proto = 0x9;
break;
default:
BUG_ON(1);
@@ -1657,12 +1656,29 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
push = evo_wait(nvd0_mast(dev), 8);
if (push) {
- evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
- evo_data(push, syncs);
- evo_data(push, magic);
- evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 1);
- evo_data(push, mode_ctrl);
- evo_kick(push, nvd0_mast(dev));
+ if (nvd0_vers(mast) < NVD0_DISP_CLASS) {
+ evo_mthd(push, 0x0600 + (nv_encoder->or * 0x040), 1);
+ evo_data(push, (depth << 16) | (proto << 8) | owner);
+ } else {
+ u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
+ u32 syncs = 0x00000001;
+
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ syncs |= 0x00000008;
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ syncs |= 0x00000010;
+
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ magic |= 0x00000001;
+
+ evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
+ evo_data(push, syncs | (depth << 6));
+ evo_data(push, magic);
+ evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 1);
+ evo_data(push, owner | (proto << 8));
+ }
+
+ evo_kick(push, mast);
}
nv_encoder->crtc = encoder->crtc;