From 78951d2226e13d4991073f1a81c4dc13aaf4a4fc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 11 Nov 2011 18:13:13 +1000 Subject: drm/nvd0/disp: send eld to the audio codec Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvd0_display.c | 66 ++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index e9da42c73371..ceb59802d694 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -765,6 +765,61 @@ nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe) return 0; } +/****************************************************************************** + * Audio + *****************************************************************************/ +static void +nvd0_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nouveau_connector *nv_connector; + struct drm_device *dev = encoder->dev; + int i, or = nv_encoder->or * 0x30; + + nv_connector = nouveau_encoder_connector_get(nv_encoder); + if (!drm_detect_monitor_audio(nv_connector->edid)) + return; + + nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000001); + + drm_edid_to_eld(&nv_connector->base, nv_connector->edid); + if (nv_connector->base.eld[0]) { + u8 *eld = nv_connector->base.eld; + + for (i = 0; i < eld[2] * 4; i++) + nv_wr32(dev, 0x10ec00 + or, (i << 8) | eld[i]); + for (i = eld[2] * 4; i < 0x60; i++) + nv_wr32(dev, 0x10ec00 + or, (i << 8) | 0x00); + + nv_mask(dev, 0x10ec10 + or, 0x80000002, 0x80000002); + } +} + +static void +nvd0_audio_disconnect(struct drm_encoder *encoder) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; + int or = nv_encoder->or * 0x30; + + nv_mask(dev, 0x10ec10 + or, 0x80000003, 0x80000000); +} + +/****************************************************************************** + * HDMI + *****************************************************************************/ +static void +nvd0_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) +{ + nvd0_audio_mode_set(encoder, mode); +} + +static void +nvd0_hdmi_disconnect(struct drm_encoder *encoder) +{ + nvd0_audio_disconnect(encoder); +} + /****************************************************************************** * SOR *****************************************************************************/ @@ -835,7 +890,8 @@ static void nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, struct drm_display_mode *mode) { - struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; + struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); struct nouveau_connector *nv_connector; @@ -858,6 +914,8 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, or_config = (mode_ctrl & 0x00000f00) >> 8; if (mode->clock >= 165000) or_config |= 0x0100; + + nvd0_hdmi_mode_set(encoder, mode); break; case OUTPUT_LVDS: or_config = (mode_ctrl & 0x00000f00) >> 8; @@ -895,12 +953,12 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON); - push = evo_wait(encoder->dev, 0, 4); + push = evo_wait(dev, 0, 4); if (push) { evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2); evo_data(push, mode_ctrl); evo_data(push, or_config); - evo_kick(push, encoder->dev, 0); + evo_kick(push, dev, 0); } nv_encoder->crtc = encoder->crtc; @@ -925,6 +983,8 @@ nvd0_sor_disconnect(struct drm_encoder *encoder) evo_kick(push, dev, 0); } + nvd0_hdmi_disconnect(encoder); + nv_encoder->crtc = NULL; nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; } -- cgit v1.2.1