/* * enable the HDMI engine */ void r600_hdmi_enable(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; uint32_t offset; u32 hdmi; if (ASIC_IS_DCE6(rdev)) return; /* Silent, r600_hdmi_enable will raise WARN for us */ if (dig->afmt->enabled) return; offset = dig->afmt->offset; /* Older chipsets require setting HDMI and routing manually */ if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { hdmi = HDMI0_ERROR_ACK | HDMI0_ENABLE; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN, ~AVIVO_TMDSA_CNTL_HDMI_EN); hdmi |= HDMI0_STREAM(HDMI0_STREAM_TMDSA); break; case ENCODER_OBJECT_ID_INTERNAL_LVTM1: WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN, ~AVIVO_LVTMA_CNTL_HDMI_EN); hdmi |= HDMI0_STREAM(HDMI0_STREAM_LVTMA); break; case ENCODER_OBJECT_ID_INTERNAL_DDI: WREG32_P(DDIA_CNTL, DDIA_HDMI_EN, ~DDIA_HDMI_EN); hdmi |= HDMI0_STREAM(HDMI0_STREAM_DDIA); break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: hdmi |= HDMI0_STREAM(HDMI0_STREAM_DVOA); break; default: dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", radeon_encoder->encoder_id); break; } WREG32(HDMI0_CONTROL + offset, hdmi); } if (rdev->irq.installed) { /* if irq is available use it */ radeon_irq_kms_enable_afmt(rdev, dig->afmt->id); } dig->afmt->enabled = true; DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", offset, radeon_encoder->encoder_id); }
/* * disable the HDMI engine */ void r600_hdmi_disable(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; uint32_t offset; if (ASIC_IS_DCE6(rdev)) return; /* Called for ATOM_ENCODER_MODE_HDMI only */ if (!dig || !dig->afmt) { return; } if (!dig->afmt->enabled) return; offset = dig->afmt->offset; DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", offset, radeon_encoder->encoder_id); /* disable irq */ radeon_irq_kms_disable_afmt(rdev, dig->afmt->id); /* Older chipsets not handled by AtomBIOS */ if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: WREG32_P(AVIVO_TMDSA_CNTL, 0, ~AVIVO_TMDSA_CNTL_HDMI_EN); break; case ENCODER_OBJECT_ID_INTERNAL_LVTM1: WREG32_P(AVIVO_LVTMA_CNTL, 0, ~AVIVO_LVTMA_CNTL_HDMI_EN); break; case ENCODER_OBJECT_ID_INTERNAL_DDI: WREG32_P(DDIA_CNTL, 0, ~DDIA_HDMI_EN); break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: break; default: dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", radeon_encoder->encoder_id); break; } WREG32(HDMI0_CONTROL + offset, HDMI0_ERROR_ACK); } dig->afmt->enabled = false; }
void evergreen_dp_enable(struct drm_encoder *encoder, bool enable) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); if (!dig || !dig->afmt) return; if (enable && drm_detect_monitor_audio(radeon_connector_edid(connector))) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector_atom_dig *dig_connector; uint32_t val; WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, AFMT_AUDIO_SAMPLE_SEND); WREG32(EVERGREEN_DP_SEC_TIMESTAMP + dig->afmt->offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1)); if (!ASIC_IS_DCE6(rdev) && radeon_connector->con_priv) { dig_connector = radeon_connector->con_priv; val = RREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset); val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf); if (dig_connector->dp_clock == 162000) val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(3); else val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(5); WREG32(EVERGREEN_DP_SEC_AUD_N + dig->afmt->offset, val); } WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, EVERGREEN_DP_SEC_ASP_ENABLE | /* Audio packet transmission */ EVERGREEN_DP_SEC_ATP_ENABLE | /* Audio timestamp packet transmission */ EVERGREEN_DP_SEC_AIP_ENABLE | /* Audio infoframe packet transmission */ EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */ } else { WREG32(EVERGREEN_DP_SEC_CNTL + dig->afmt->offset, 0); WREG32_AND(AFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, ~AFMT_AUDIO_SAMPLE_SEND); } dig->afmt->enabled = enable; }