1e55d3e6cSRafał Miłecki /* 2e55d3e6cSRafał Miłecki * Copyright 2008 Advanced Micro Devices, Inc. 3e55d3e6cSRafał Miłecki * Copyright 2008 Red Hat Inc. 4e55d3e6cSRafał Miłecki * Copyright 2009 Christian König. 5e55d3e6cSRafał Miłecki * 6e55d3e6cSRafał Miłecki * Permission is hereby granted, free of charge, to any person obtaining a 7e55d3e6cSRafał Miłecki * copy of this software and associated documentation files (the "Software"), 8e55d3e6cSRafał Miłecki * to deal in the Software without restriction, including without limitation 9e55d3e6cSRafał Miłecki * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10e55d3e6cSRafał Miłecki * and/or sell copies of the Software, and to permit persons to whom the 11e55d3e6cSRafał Miłecki * Software is furnished to do so, subject to the following conditions: 12e55d3e6cSRafał Miłecki * 13e55d3e6cSRafał Miłecki * The above copyright notice and this permission notice shall be included in 14e55d3e6cSRafał Miłecki * all copies or substantial portions of the Software. 15e55d3e6cSRafał Miłecki * 16e55d3e6cSRafał Miłecki * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17e55d3e6cSRafał Miłecki * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18e55d3e6cSRafał Miłecki * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19e55d3e6cSRafał Miłecki * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20e55d3e6cSRafał Miłecki * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21e55d3e6cSRafał Miłecki * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22e55d3e6cSRafał Miłecki * OTHER DEALINGS IN THE SOFTWARE. 23e55d3e6cSRafał Miłecki * 24e55d3e6cSRafał Miłecki * Authors: Christian König 25e55d3e6cSRafał Miłecki * Rafał Miłecki 26e55d3e6cSRafał Miłecki */ 27e3b2e034SThierry Reding #include <linux/hdmi.h> 28760285e7SDavid Howells #include <drm/drmP.h> 29760285e7SDavid Howells #include <drm/radeon_drm.h> 30e55d3e6cSRafał Miłecki #include "radeon.h" 31e55d3e6cSRafał Miłecki #include "radeon_asic.h" 32e55d3e6cSRafał Miłecki #include "evergreend.h" 33e55d3e6cSRafał Miłecki #include "atom.h" 34e55d3e6cSRafał Miłecki 35e55d3e6cSRafał Miłecki /* 36e55d3e6cSRafał Miłecki * update the N and CTS parameters for a given pixel clock rate 37e55d3e6cSRafał Miłecki */ 38e55d3e6cSRafał Miłecki static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock) 39e55d3e6cSRafał Miłecki { 40e55d3e6cSRafał Miłecki struct drm_device *dev = encoder->dev; 41e55d3e6cSRafał Miłecki struct radeon_device *rdev = dev->dev_private; 42e55d3e6cSRafał Miłecki struct radeon_hdmi_acr acr = r600_hdmi_acr(clock); 43cfcbd6d3SRafał Miłecki struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 44cfcbd6d3SRafał Miłecki struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 45cfcbd6d3SRafał Miłecki uint32_t offset = dig->afmt->offset; 46e55d3e6cSRafał Miłecki 47e55d3e6cSRafał Miłecki WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr.cts_32khz)); 48e55d3e6cSRafał Miłecki WREG32(HDMI_ACR_32_1 + offset, acr.n_32khz); 49e55d3e6cSRafał Miłecki 50e55d3e6cSRafał Miłecki WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr.cts_44_1khz)); 51e55d3e6cSRafał Miłecki WREG32(HDMI_ACR_44_1 + offset, acr.n_44_1khz); 52e55d3e6cSRafał Miłecki 53e55d3e6cSRafał Miłecki WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr.cts_48khz)); 54e55d3e6cSRafał Miłecki WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz); 55e55d3e6cSRafał Miłecki } 56e55d3e6cSRafał Miłecki 57e55d3e6cSRafał Miłecki /* 58e55d3e6cSRafał Miłecki * build a HDMI Video Info Frame 59e55d3e6cSRafał Miłecki */ 60e3b2e034SThierry Reding static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder, 61e3b2e034SThierry Reding void *buffer, size_t size) 62e55d3e6cSRafał Miłecki { 63e55d3e6cSRafał Miłecki struct drm_device *dev = encoder->dev; 64e55d3e6cSRafał Miłecki struct radeon_device *rdev = dev->dev_private; 65cfcbd6d3SRafał Miłecki struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 66cfcbd6d3SRafał Miłecki struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 67cfcbd6d3SRafał Miłecki uint32_t offset = dig->afmt->offset; 68e3b2e034SThierry Reding uint8_t *frame = buffer + 3; 69e55d3e6cSRafał Miłecki 70e55d3e6cSRafał Miłecki /* Our header values (type, version, length) should be alright, Intel 71e55d3e6cSRafał Miłecki * is using the same. Checksum function also seems to be OK, it works 72e55d3e6cSRafał Miłecki * fine for audio infoframe. However calculated value is always lower 73e55d3e6cSRafał Miłecki * by 2 in comparison to fglrx. It breaks displaying anything in case 74e55d3e6cSRafał Miłecki * of TVs that strictly check the checksum. Hack it manually here to 75e55d3e6cSRafał Miłecki * workaround this issue. */ 76e55d3e6cSRafał Miłecki frame[0x0] += 2; 77e55d3e6cSRafał Miłecki 78e55d3e6cSRafał Miłecki WREG32(AFMT_AVI_INFO0 + offset, 79e55d3e6cSRafał Miłecki frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); 80e55d3e6cSRafał Miłecki WREG32(AFMT_AVI_INFO1 + offset, 81e55d3e6cSRafał Miłecki frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24)); 82e55d3e6cSRafał Miłecki WREG32(AFMT_AVI_INFO2 + offset, 83e55d3e6cSRafał Miłecki frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); 84e55d3e6cSRafał Miłecki WREG32(AFMT_AVI_INFO3 + offset, 85e55d3e6cSRafał Miłecki frame[0xC] | (frame[0xD] << 8)); 86e55d3e6cSRafał Miłecki } 87e55d3e6cSRafał Miłecki 88*b1f6f47eSAlex Deucher static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock) 89*b1f6f47eSAlex Deucher { 90*b1f6f47eSAlex Deucher struct drm_device *dev = encoder->dev; 91*b1f6f47eSAlex Deucher struct radeon_device *rdev = dev->dev_private; 92*b1f6f47eSAlex Deucher struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 93*b1f6f47eSAlex Deucher struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 94*b1f6f47eSAlex Deucher struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); 95*b1f6f47eSAlex Deucher u32 base_rate = 48000; 96*b1f6f47eSAlex Deucher 97*b1f6f47eSAlex Deucher if (!dig || !dig->afmt) 98*b1f6f47eSAlex Deucher return; 99*b1f6f47eSAlex Deucher 100*b1f6f47eSAlex Deucher /* XXX: properly calculate this */ 101*b1f6f47eSAlex Deucher /* XXX two dtos; generally use dto0 for hdmi */ 102*b1f6f47eSAlex Deucher /* Express [24MHz / target pixel clock] as an exact rational 103*b1f6f47eSAlex Deucher * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE 104*b1f6f47eSAlex Deucher * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator 105*b1f6f47eSAlex Deucher */ 106*b1f6f47eSAlex Deucher WREG32(DCCG_AUDIO_DTO0_PHASE, (base_rate*50) & 0xffffff); 107*b1f6f47eSAlex Deucher WREG32(DCCG_AUDIO_DTO0_MODULE, (clock*100) & 0xffffff); 108*b1f6f47eSAlex Deucher WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id)); 109*b1f6f47eSAlex Deucher } 110*b1f6f47eSAlex Deucher 111*b1f6f47eSAlex Deucher 112e55d3e6cSRafał Miłecki /* 113e55d3e6cSRafał Miłecki * update the info frames with the data from the current display mode 114e55d3e6cSRafał Miłecki */ 115e55d3e6cSRafał Miłecki void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) 116e55d3e6cSRafał Miłecki { 117e55d3e6cSRafał Miłecki struct drm_device *dev = encoder->dev; 118e55d3e6cSRafał Miłecki struct radeon_device *rdev = dev->dev_private; 119cfcbd6d3SRafał Miłecki struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 120cfcbd6d3SRafał Miłecki struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 121e3b2e034SThierry Reding u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE]; 122e3b2e034SThierry Reding struct hdmi_avi_infoframe frame; 123cfcbd6d3SRafał Miłecki uint32_t offset; 124e3b2e034SThierry Reding ssize_t err; 125e55d3e6cSRafał Miłecki 126cfcbd6d3SRafał Miłecki /* Silent, r600_hdmi_enable will raise WARN for us */ 127cfcbd6d3SRafał Miłecki if (!dig->afmt->enabled) 128e55d3e6cSRafał Miłecki return; 129cfcbd6d3SRafał Miłecki offset = dig->afmt->offset; 130e55d3e6cSRafał Miłecki 131*b1f6f47eSAlex Deucher evergreen_audio_set_dto(encoder, mode->clock); 132e55d3e6cSRafał Miłecki 1331c3439f2SRafał Miłecki WREG32(HDMI_VBI_PACKET_CONTROL + offset, 1341c3439f2SRafał Miłecki HDMI_NULL_SEND); /* send null packets when required */ 1351c3439f2SRafał Miłecki 136e55d3e6cSRafał Miłecki WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000); 137e55d3e6cSRafał Miłecki 1381c3439f2SRafał Miłecki WREG32(HDMI_VBI_PACKET_CONTROL + offset, 1391c3439f2SRafał Miłecki HDMI_NULL_SEND | /* send null packets when required */ 1401c3439f2SRafał Miłecki HDMI_GC_SEND | /* send general control packets */ 1411c3439f2SRafał Miłecki HDMI_GC_CONT); /* send general control packets every frame */ 142e55d3e6cSRafał Miłecki 1431c3439f2SRafał Miłecki WREG32(HDMI_INFOFRAME_CONTROL0 + offset, 1441c3439f2SRafał Miłecki HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ 1451c3439f2SRafał Miłecki HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */ 1461c3439f2SRafał Miłecki 1471c3439f2SRafał Miłecki WREG32(AFMT_INFOFRAME_CONTROL0 + offset, 1481c3439f2SRafał Miłecki AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ 1491c3439f2SRafał Miłecki 1501c3439f2SRafał Miłecki WREG32(HDMI_INFOFRAME_CONTROL1 + offset, 1511c3439f2SRafał Miłecki HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */ 1521c3439f2SRafał Miłecki 1531c3439f2SRafał Miłecki WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */ 154e55d3e6cSRafał Miłecki 15591a44019SRafał Miłecki WREG32(HDMI_AUDIO_PACKET_CONTROL + offset, 15691a44019SRafał Miłecki HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */ 15791a44019SRafał Miłecki HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ 15891a44019SRafał Miłecki 15991a44019SRafał Miłecki WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, 16091a44019SRafał Miłecki AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ 16191a44019SRafał Miłecki 16291a44019SRafał Miłecki /* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */ 16391a44019SRafał Miłecki 16491a44019SRafał Miłecki WREG32(HDMI_ACR_PACKET_CONTROL + offset, 16591a44019SRafał Miłecki HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */ 16691a44019SRafał Miłecki HDMI_ACR_SOURCE); /* select SW CTS value */ 16791a44019SRafał Miłecki 16891a44019SRafał Miłecki evergreen_hdmi_update_ACR(encoder, mode->clock); 16991a44019SRafał Miłecki 170f93e3fc3SRafał Miłecki WREG32(AFMT_60958_0 + offset, 171f93e3fc3SRafał Miłecki AFMT_60958_CS_CHANNEL_NUMBER_L(1)); 172f93e3fc3SRafał Miłecki 173f93e3fc3SRafał Miłecki WREG32(AFMT_60958_1 + offset, 174f93e3fc3SRafał Miłecki AFMT_60958_CS_CHANNEL_NUMBER_R(2)); 175f93e3fc3SRafał Miłecki 176f93e3fc3SRafał Miłecki WREG32(AFMT_60958_2 + offset, 177f93e3fc3SRafał Miłecki AFMT_60958_CS_CHANNEL_NUMBER_2(3) | 178f93e3fc3SRafał Miłecki AFMT_60958_CS_CHANNEL_NUMBER_3(4) | 179f93e3fc3SRafał Miłecki AFMT_60958_CS_CHANNEL_NUMBER_4(5) | 180f93e3fc3SRafał Miłecki AFMT_60958_CS_CHANNEL_NUMBER_5(6) | 181f93e3fc3SRafał Miłecki AFMT_60958_CS_CHANNEL_NUMBER_6(7) | 182f93e3fc3SRafał Miłecki AFMT_60958_CS_CHANNEL_NUMBER_7(8)); 183f93e3fc3SRafał Miłecki 184f93e3fc3SRafał Miłecki /* fglrx sets 0x0001005f | (x & 0x00fc0000) in 0x5f78 here */ 185f93e3fc3SRafał Miłecki 186f93e3fc3SRafał Miłecki WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset, 187f93e3fc3SRafał Miłecki AFMT_AUDIO_CHANNEL_ENABLE(0xff)); 188f93e3fc3SRafał Miłecki 189f93e3fc3SRafał Miłecki /* fglrx sets 0x40 in 0x5f80 here */ 190f93e3fc3SRafał Miłecki 191e3b2e034SThierry Reding err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); 192e3b2e034SThierry Reding if (err < 0) { 193e3b2e034SThierry Reding DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); 194e3b2e034SThierry Reding return; 195e3b2e034SThierry Reding } 196e55d3e6cSRafał Miłecki 197e3b2e034SThierry Reding err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); 198e3b2e034SThierry Reding if (err < 0) { 199e3b2e034SThierry Reding DRM_ERROR("failed to pack AVI infoframe: %zd\n", err); 200e3b2e034SThierry Reding return; 201e3b2e034SThierry Reding } 202e3b2e034SThierry Reding 203e3b2e034SThierry Reding evergreen_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer)); 2041c3439f2SRafał Miłecki 205d3418eacSRafał Miłecki WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset, 206d3418eacSRafał Miłecki HDMI_AVI_INFO_SEND | /* enable AVI info frames */ 207d3418eacSRafał Miłecki HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */ 208d3418eacSRafał Miłecki 209d3418eacSRafał Miłecki WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset, 210d3418eacSRafał Miłecki HDMI_AVI_INFO_LINE(2), /* anything other than 0 */ 211d3418eacSRafał Miłecki ~HDMI_AVI_INFO_LINE_MASK); 212d3418eacSRafał Miłecki 213d3418eacSRafał Miłecki WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset, 214d3418eacSRafał Miłecki AFMT_AUDIO_SAMPLE_SEND); /* send audio packets */ 215d3418eacSRafał Miłecki 216e55d3e6cSRafał Miłecki /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ 217e55d3e6cSRafał Miłecki WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF); 218e55d3e6cSRafał Miłecki WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF); 219e55d3e6cSRafał Miłecki WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001); 220e55d3e6cSRafał Miłecki WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001); 221e55d3e6cSRafał Miłecki } 222