/* * Copyright 2008 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * Copyright 2009 Christian König. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Christian König
*/ #include <linux/hdmi.h> #include <linux/gcd.h>
WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset,
HDMI0_AVI_INFO_LINE(2)); /* anything other than 0 */
WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
HDMI0_AVI_INFO_CONT); /* send AVI info frames every frame/field */
/* * have buffer status changed since last call?
*/ int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder)
{ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; int status, result;
if (!dig->afmt || !dig->afmt->enabled) return 0;
status = r600_hdmi_is_audio_buffer_filled(encoder);
result = dig->afmt->last_buffer_filled_status != status;
dig->afmt->last_buffer_filled_status = status;
WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset,
HDMI0_NULL_SEND | /* send null packets when required */
HDMI0_GC_SEND | /* send general control packets */
HDMI0_GC_CONT); /* send general control packets every frame */
}
WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset,
HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */
~(HDMI0_AUDIO_SAMPLE_SEND |
HDMI0_AUDIO_DELAY_EN_MASK |
HDMI0_AUDIO_PACKETS_PER_LINE_MASK |
HDMI0_60958_CS_UPDATE));
WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
WREG32_P(HDMI0_INFOFRAME_CONTROL1 + offset,
HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */
~HDMI0_AUDIO_INFO_LINE_MASK);
if (!dig->afmt || !dig->afmt->enabled) return;
offset = dig->afmt->offset;
DRM_DEBUG("%s with %d channels, %d Hz sampling rate, %d bits per sample,\n",
r600_hdmi_is_audio_buffer_filled(encoder) ? "playing" : "stopped",
audio.channels, audio.rate, audio.bits_per_sample);
DRM_DEBUG("0x%02X IEC60958 status bits and 0x%02X category code\n",
(int)audio.status_bits, (int)audio.category_code);
err = hdmi_audio_infoframe_init(&frame); if (err < 0) {
DRM_ERROR("failed to setup audio infoframe\n"); return;
}
frame.channels = audio.channels;
err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); if (err < 0) {
DRM_ERROR("failed to pack audio infoframe\n"); return;
}
value = RREG32(HDMI0_AUDIO_PACKET_CONTROL + offset); if (value & HDMI0_AUDIO_TEST_EN)
WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
value & ~HDMI0_AUDIO_TEST_EN);
/* Older chipsets require setting HDMI and routing manually */ if (!ASIC_IS_DCE3(rdev)) { if (enable)
hdmi |= HDMI0_ENABLE; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: if (enable) {
WREG32_OR(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN);
hdmi |= HDMI0_STREAM(HDMI0_STREAM_TMDSA);
} else {
WREG32_AND(AVIVO_TMDSA_CNTL, ~AVIVO_TMDSA_CNTL_HDMI_EN);
} break; case ENCODER_OBJECT_ID_INTERNAL_LVTM1: if (enable) {
WREG32_OR(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN);
hdmi |= HDMI0_STREAM(HDMI0_STREAM_LVTMA);
} else {
WREG32_AND(AVIVO_LVTMA_CNTL, ~AVIVO_LVTMA_CNTL_HDMI_EN);
} break; case ENCODER_OBJECT_ID_INTERNAL_DDI: if (enable) {
WREG32_OR(DDIA_CNTL, DDIA_HDMI_EN);
hdmi |= HDMI0_STREAM(HDMI0_STREAM_DDIA);
} else {
WREG32_AND(DDIA_CNTL, ~DDIA_HDMI_EN);
} break; case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: if (enable)
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 + dig->afmt->offset, hdmi);
}
if (rdev->irq.installed) { /* if irq is available use it */ /* XXX: shouldn't need this on any asics. Double check DCE2/3 */ if (enable)
radeon_irq_kms_enable_afmt(rdev, dig->afmt->id); else
radeon_irq_kms_disable_afmt(rdev, dig->afmt->id);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.