18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2013 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * Copyright 2014 Rafał Miłecki 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 78c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 88c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 98c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 108c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 138c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 198c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 208c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 218c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci#include <linux/hdmi.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "radeon.h" 268c2ecf20Sopenharmony_ci#include "radeon_asic.h" 278c2ecf20Sopenharmony_ci#include "radeon_audio.h" 288c2ecf20Sopenharmony_ci#include "r600d.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_civoid dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder, 318c2ecf20Sopenharmony_ci u8 *sadb, int sad_count) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 348c2ecf20Sopenharmony_ci u32 tmp; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* program the speaker allocation */ 378c2ecf20Sopenharmony_ci tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); 388c2ecf20Sopenharmony_ci tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK); 398c2ecf20Sopenharmony_ci /* set HDMI mode */ 408c2ecf20Sopenharmony_ci tmp |= HDMI_CONNECTION; 418c2ecf20Sopenharmony_ci if (sad_count) 428c2ecf20Sopenharmony_ci tmp |= SPEAKER_ALLOCATION(sadb[0]); 438c2ecf20Sopenharmony_ci else 448c2ecf20Sopenharmony_ci tmp |= SPEAKER_ALLOCATION(5); /* stereo */ 458c2ecf20Sopenharmony_ci WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_civoid dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder, 498c2ecf20Sopenharmony_ci u8 *sadb, int sad_count) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 528c2ecf20Sopenharmony_ci u32 tmp; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* program the speaker allocation */ 558c2ecf20Sopenharmony_ci tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER); 568c2ecf20Sopenharmony_ci tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK); 578c2ecf20Sopenharmony_ci /* set DP mode */ 588c2ecf20Sopenharmony_ci tmp |= DP_CONNECTION; 598c2ecf20Sopenharmony_ci if (sad_count) 608c2ecf20Sopenharmony_ci tmp |= SPEAKER_ALLOCATION(sadb[0]); 618c2ecf20Sopenharmony_ci else 628c2ecf20Sopenharmony_ci tmp |= SPEAKER_ALLOCATION(5); /* stereo */ 638c2ecf20Sopenharmony_ci WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_civoid dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder, 678c2ecf20Sopenharmony_ci struct cea_sad *sads, int sad_count) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci int i; 708c2ecf20Sopenharmony_ci struct radeon_device *rdev = encoder->dev->dev_private; 718c2ecf20Sopenharmony_ci static const u16 eld_reg_to_type[][2] = { 728c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM }, 738c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 }, 748c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 }, 758c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 }, 768c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 }, 778c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC }, 788c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS }, 798c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC }, 808c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 }, 818c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD }, 828c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP }, 838c2ecf20Sopenharmony_ci { AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO }, 848c2ecf20Sopenharmony_ci }; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) { 878c2ecf20Sopenharmony_ci u32 value = 0; 888c2ecf20Sopenharmony_ci u8 stereo_freqs = 0; 898c2ecf20Sopenharmony_ci int max_channels = -1; 908c2ecf20Sopenharmony_ci int j; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci for (j = 0; j < sad_count; j++) { 938c2ecf20Sopenharmony_ci struct cea_sad *sad = &sads[j]; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (sad->format == eld_reg_to_type[i][1]) { 968c2ecf20Sopenharmony_ci if (sad->channels > max_channels) { 978c2ecf20Sopenharmony_ci value = MAX_CHANNELS(sad->channels) | 988c2ecf20Sopenharmony_ci DESCRIPTOR_BYTE_2(sad->byte2) | 998c2ecf20Sopenharmony_ci SUPPORTED_FREQUENCIES(sad->freq); 1008c2ecf20Sopenharmony_ci max_channels = sad->channels; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM) 1048c2ecf20Sopenharmony_ci stereo_freqs |= sad->freq; 1058c2ecf20Sopenharmony_ci else 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_civoid dce3_2_audio_set_dto(struct radeon_device *rdev, 1178c2ecf20Sopenharmony_ci struct radeon_crtc *crtc, unsigned int clock) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder; 1208c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *dig; 1218c2ecf20Sopenharmony_ci unsigned int max_ratio = clock / 24000; 1228c2ecf20Sopenharmony_ci u32 dto_phase; 1238c2ecf20Sopenharmony_ci u32 wallclock_ratio; 1248c2ecf20Sopenharmony_ci u32 dto_cntl; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (!crtc) 1278c2ecf20Sopenharmony_ci return; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci radeon_encoder = to_radeon_encoder(crtc->encoder); 1308c2ecf20Sopenharmony_ci dig = radeon_encoder->enc_priv; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (!dig) 1338c2ecf20Sopenharmony_ci return; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (max_ratio >= 8) { 1368c2ecf20Sopenharmony_ci dto_phase = 192 * 1000; 1378c2ecf20Sopenharmony_ci wallclock_ratio = 3; 1388c2ecf20Sopenharmony_ci } else if (max_ratio >= 4) { 1398c2ecf20Sopenharmony_ci dto_phase = 96 * 1000; 1408c2ecf20Sopenharmony_ci wallclock_ratio = 2; 1418c2ecf20Sopenharmony_ci } else if (max_ratio >= 2) { 1428c2ecf20Sopenharmony_ci dto_phase = 48 * 1000; 1438c2ecf20Sopenharmony_ci wallclock_ratio = 1; 1448c2ecf20Sopenharmony_ci } else { 1458c2ecf20Sopenharmony_ci dto_phase = 24 * 1000; 1468c2ecf20Sopenharmony_ci wallclock_ratio = 0; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* Express [24MHz / target pixel clock] as an exact rational 1508c2ecf20Sopenharmony_ci * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE 1518c2ecf20Sopenharmony_ci * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci if (dig->dig_encoder == 0) { 1548c2ecf20Sopenharmony_ci dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; 1558c2ecf20Sopenharmony_ci dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); 1568c2ecf20Sopenharmony_ci WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl); 1578c2ecf20Sopenharmony_ci WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase); 1588c2ecf20Sopenharmony_ci WREG32(DCCG_AUDIO_DTO0_MODULE, clock); 1598c2ecf20Sopenharmony_ci WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ 1608c2ecf20Sopenharmony_ci } else { 1618c2ecf20Sopenharmony_ci dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK; 1628c2ecf20Sopenharmony_ci dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio); 1638c2ecf20Sopenharmony_ci WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl); 1648c2ecf20Sopenharmony_ci WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase); 1658c2ecf20Sopenharmony_ci WREG32(DCCG_AUDIO_DTO1_MODULE, clock); 1668c2ecf20Sopenharmony_ci WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */ 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_civoid dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset, 1718c2ecf20Sopenharmony_ci const struct radeon_hdmi_acr *acr) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 1748c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci WREG32(DCE3_HDMI0_ACR_PACKET_CONTROL + offset, 1778c2ecf20Sopenharmony_ci HDMI0_ACR_SOURCE | /* select SW CTS value */ 1788c2ecf20Sopenharmony_ci HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci WREG32_P(HDMI0_ACR_32_0 + offset, 1818c2ecf20Sopenharmony_ci HDMI0_ACR_CTS_32(acr->cts_32khz), 1828c2ecf20Sopenharmony_ci ~HDMI0_ACR_CTS_32_MASK); 1838c2ecf20Sopenharmony_ci WREG32_P(HDMI0_ACR_32_1 + offset, 1848c2ecf20Sopenharmony_ci HDMI0_ACR_N_32(acr->n_32khz), 1858c2ecf20Sopenharmony_ci ~HDMI0_ACR_N_32_MASK); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci WREG32_P(HDMI0_ACR_44_0 + offset, 1888c2ecf20Sopenharmony_ci HDMI0_ACR_CTS_44(acr->cts_44_1khz), 1898c2ecf20Sopenharmony_ci ~HDMI0_ACR_CTS_44_MASK); 1908c2ecf20Sopenharmony_ci WREG32_P(HDMI0_ACR_44_1 + offset, 1918c2ecf20Sopenharmony_ci HDMI0_ACR_N_44(acr->n_44_1khz), 1928c2ecf20Sopenharmony_ci ~HDMI0_ACR_N_44_MASK); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci WREG32_P(HDMI0_ACR_48_0 + offset, 1958c2ecf20Sopenharmony_ci HDMI0_ACR_CTS_48(acr->cts_48khz), 1968c2ecf20Sopenharmony_ci ~HDMI0_ACR_CTS_48_MASK); 1978c2ecf20Sopenharmony_ci WREG32_P(HDMI0_ACR_48_1 + offset, 1988c2ecf20Sopenharmony_ci HDMI0_ACR_N_48(acr->n_48khz), 1998c2ecf20Sopenharmony_ci ~HDMI0_ACR_N_48_MASK); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_civoid dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 2058c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, 2088c2ecf20Sopenharmony_ci HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ 2098c2ecf20Sopenharmony_ci HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, 2128c2ecf20Sopenharmony_ci AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */ 2138c2ecf20Sopenharmony_ci AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset, 2168c2ecf20Sopenharmony_ci HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ 2178c2ecf20Sopenharmony_ci HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */ 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset, 2208c2ecf20Sopenharmony_ci HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */ 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_civoid dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 2268c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (mute) 2298c2ecf20Sopenharmony_ci WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE); 2308c2ecf20Sopenharmony_ci else 2318c2ecf20Sopenharmony_ci WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE); 2328c2ecf20Sopenharmony_ci} 233