1254885Sdumbbell/* 2254885Sdumbbell * Copyright 2008 Advanced Micro Devices, Inc. 3254885Sdumbbell * Copyright 2008 Red Hat Inc. 4254885Sdumbbell * Copyright 2009 Christian K��nig. 5254885Sdumbbell * 6254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 7254885Sdumbbell * copy of this software and associated documentation files (the "Software"), 8254885Sdumbbell * to deal in the Software without restriction, including without limitation 9254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the 11254885Sdumbbell * Software is furnished to do so, subject to the following conditions: 12254885Sdumbbell * 13254885Sdumbbell * The above copyright notice and this permission notice shall be included in 14254885Sdumbbell * all copies or substantial portions of the Software. 15254885Sdumbbell * 16254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE. 23254885Sdumbbell * 24254885Sdumbbell * Authors: Christian K��nig 25254885Sdumbbell * Rafa�� Mi��ecki 26254885Sdumbbell */ 27254885Sdumbbell 28254885Sdumbbell#include <sys/cdefs.h> 29254885Sdumbbell__FBSDID("$FreeBSD: releng/10.3/sys/dev/drm2/radeon/evergreen_hdmi.c 254885 2013-08-25 19:37:15Z dumbbell $"); 30254885Sdumbbell 31254885Sdumbbell#include <dev/drm2/drmP.h> 32254885Sdumbbell#include <dev/drm2/radeon/radeon_drm.h> 33254885Sdumbbell#include "radeon.h" 34254885Sdumbbell#include "radeon_asic.h" 35254885Sdumbbell#include "evergreend.h" 36254885Sdumbbell#include "atom.h" 37254885Sdumbbell 38254885Sdumbbell/* 39254885Sdumbbell * update the N and CTS parameters for a given pixel clock rate 40254885Sdumbbell */ 41254885Sdumbbellstatic void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock) 42254885Sdumbbell{ 43254885Sdumbbell struct drm_device *dev = encoder->dev; 44254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 45254885Sdumbbell struct radeon_hdmi_acr acr = r600_hdmi_acr(clock); 46254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 47254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 48254885Sdumbbell uint32_t offset = dig->afmt->offset; 49254885Sdumbbell 50254885Sdumbbell WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr.cts_32khz)); 51254885Sdumbbell WREG32(HDMI_ACR_32_1 + offset, acr.n_32khz); 52254885Sdumbbell 53254885Sdumbbell WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr.cts_44_1khz)); 54254885Sdumbbell WREG32(HDMI_ACR_44_1 + offset, acr.n_44_1khz); 55254885Sdumbbell 56254885Sdumbbell WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr.cts_48khz)); 57254885Sdumbbell WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz); 58254885Sdumbbell} 59254885Sdumbbell 60254885Sdumbbell/* 61254885Sdumbbell * calculate the crc for a given info frame 62254885Sdumbbell */ 63254885Sdumbbellstatic void evergreen_hdmi_infoframe_checksum(uint8_t packetType, 64254885Sdumbbell uint8_t versionNumber, 65254885Sdumbbell uint8_t length, 66254885Sdumbbell uint8_t *frame) 67254885Sdumbbell{ 68254885Sdumbbell int i; 69254885Sdumbbell frame[0] = packetType + versionNumber + length; 70254885Sdumbbell for (i = 1; i <= length; i++) 71254885Sdumbbell frame[0] += frame[i]; 72254885Sdumbbell frame[0] = 0x100 - frame[0]; 73254885Sdumbbell} 74254885Sdumbbell 75254885Sdumbbell/* 76254885Sdumbbell * build a HDMI Video Info Frame 77254885Sdumbbell */ 78254885Sdumbbellstatic void evergreen_hdmi_videoinfoframe( 79254885Sdumbbell struct drm_encoder *encoder, 80254885Sdumbbell uint8_t color_format, 81254885Sdumbbell int active_information_present, 82254885Sdumbbell uint8_t active_format_aspect_ratio, 83254885Sdumbbell uint8_t scan_information, 84254885Sdumbbell uint8_t colorimetry, 85254885Sdumbbell uint8_t ex_colorimetry, 86254885Sdumbbell uint8_t quantization, 87254885Sdumbbell int ITC, 88254885Sdumbbell uint8_t picture_aspect_ratio, 89254885Sdumbbell uint8_t video_format_identification, 90254885Sdumbbell uint8_t pixel_repetition, 91254885Sdumbbell uint8_t non_uniform_picture_scaling, 92254885Sdumbbell uint8_t bar_info_data_valid, 93254885Sdumbbell uint16_t top_bar, 94254885Sdumbbell uint16_t bottom_bar, 95254885Sdumbbell uint16_t left_bar, 96254885Sdumbbell uint16_t right_bar 97254885Sdumbbell) 98254885Sdumbbell{ 99254885Sdumbbell struct drm_device *dev = encoder->dev; 100254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 101254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 102254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 103254885Sdumbbell uint32_t offset = dig->afmt->offset; 104254885Sdumbbell 105254885Sdumbbell uint8_t frame[14]; 106254885Sdumbbell 107254885Sdumbbell frame[0x0] = 0; 108254885Sdumbbell frame[0x1] = 109254885Sdumbbell (scan_information & 0x3) | 110254885Sdumbbell ((bar_info_data_valid & 0x3) << 2) | 111254885Sdumbbell ((active_information_present & 0x1) << 4) | 112254885Sdumbbell ((color_format & 0x3) << 5); 113254885Sdumbbell frame[0x2] = 114254885Sdumbbell (active_format_aspect_ratio & 0xF) | 115254885Sdumbbell ((picture_aspect_ratio & 0x3) << 4) | 116254885Sdumbbell ((colorimetry & 0x3) << 6); 117254885Sdumbbell frame[0x3] = 118254885Sdumbbell (non_uniform_picture_scaling & 0x3) | 119254885Sdumbbell ((quantization & 0x3) << 2) | 120254885Sdumbbell ((ex_colorimetry & 0x7) << 4) | 121254885Sdumbbell ((ITC & 0x1) << 7); 122254885Sdumbbell frame[0x4] = (video_format_identification & 0x7F); 123254885Sdumbbell frame[0x5] = (pixel_repetition & 0xF); 124254885Sdumbbell frame[0x6] = (top_bar & 0xFF); 125254885Sdumbbell frame[0x7] = (top_bar >> 8); 126254885Sdumbbell frame[0x8] = (bottom_bar & 0xFF); 127254885Sdumbbell frame[0x9] = (bottom_bar >> 8); 128254885Sdumbbell frame[0xA] = (left_bar & 0xFF); 129254885Sdumbbell frame[0xB] = (left_bar >> 8); 130254885Sdumbbell frame[0xC] = (right_bar & 0xFF); 131254885Sdumbbell frame[0xD] = (right_bar >> 8); 132254885Sdumbbell 133254885Sdumbbell evergreen_hdmi_infoframe_checksum(0x82, 0x02, 0x0D, frame); 134254885Sdumbbell /* Our header values (type, version, length) should be alright, Intel 135254885Sdumbbell * is using the same. Checksum function also seems to be OK, it works 136254885Sdumbbell * fine for audio infoframe. However calculated value is always lower 137254885Sdumbbell * by 2 in comparison to fglrx. It breaks displaying anything in case 138254885Sdumbbell * of TVs that strictly check the checksum. Hack it manually here to 139254885Sdumbbell * workaround this issue. */ 140254885Sdumbbell frame[0x0] += 2; 141254885Sdumbbell 142254885Sdumbbell WREG32(AFMT_AVI_INFO0 + offset, 143254885Sdumbbell frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); 144254885Sdumbbell WREG32(AFMT_AVI_INFO1 + offset, 145254885Sdumbbell frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24)); 146254885Sdumbbell WREG32(AFMT_AVI_INFO2 + offset, 147254885Sdumbbell frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); 148254885Sdumbbell WREG32(AFMT_AVI_INFO3 + offset, 149254885Sdumbbell frame[0xC] | (frame[0xD] << 8)); 150254885Sdumbbell} 151254885Sdumbbell 152254885Sdumbbell/* 153254885Sdumbbell * update the info frames with the data from the current display mode 154254885Sdumbbell */ 155254885Sdumbbellvoid evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) 156254885Sdumbbell{ 157254885Sdumbbell struct drm_device *dev = encoder->dev; 158254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 159254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 160254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 161254885Sdumbbell uint32_t offset; 162254885Sdumbbell 163254885Sdumbbell /* Silent, r600_hdmi_enable will raise WARN for us */ 164254885Sdumbbell if (!dig->afmt->enabled) 165254885Sdumbbell return; 166254885Sdumbbell offset = dig->afmt->offset; 167254885Sdumbbell 168254885Sdumbbell r600_audio_set_clock(encoder, mode->clock); 169254885Sdumbbell 170254885Sdumbbell WREG32(HDMI_VBI_PACKET_CONTROL + offset, 171254885Sdumbbell HDMI_NULL_SEND); /* send null packets when required */ 172254885Sdumbbell 173254885Sdumbbell WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000); 174254885Sdumbbell 175254885Sdumbbell WREG32(HDMI_AUDIO_PACKET_CONTROL + offset, 176254885Sdumbbell HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */ 177254885Sdumbbell HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ 178254885Sdumbbell 179254885Sdumbbell WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, 180254885Sdumbbell AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */ 181254885Sdumbbell AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ 182254885Sdumbbell 183254885Sdumbbell WREG32(HDMI_ACR_PACKET_CONTROL + offset, 184254885Sdumbbell HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */ 185254885Sdumbbell HDMI_ACR_SOURCE); /* select SW CTS value */ 186254885Sdumbbell 187254885Sdumbbell WREG32(HDMI_VBI_PACKET_CONTROL + offset, 188254885Sdumbbell HDMI_NULL_SEND | /* send null packets when required */ 189254885Sdumbbell HDMI_GC_SEND | /* send general control packets */ 190254885Sdumbbell HDMI_GC_CONT); /* send general control packets every frame */ 191254885Sdumbbell 192254885Sdumbbell WREG32(HDMI_INFOFRAME_CONTROL0 + offset, 193254885Sdumbbell HDMI_AVI_INFO_SEND | /* enable AVI info frames */ 194254885Sdumbbell HDMI_AVI_INFO_CONT | /* send AVI info frames every frame/field */ 195254885Sdumbbell HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ 196254885Sdumbbell HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */ 197254885Sdumbbell 198254885Sdumbbell WREG32(AFMT_INFOFRAME_CONTROL0 + offset, 199254885Sdumbbell AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ 200254885Sdumbbell 201254885Sdumbbell WREG32(HDMI_INFOFRAME_CONTROL1 + offset, 202254885Sdumbbell HDMI_AVI_INFO_LINE(2) | /* anything other than 0 */ 203254885Sdumbbell HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */ 204254885Sdumbbell 205254885Sdumbbell WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */ 206254885Sdumbbell 207254885Sdumbbell evergreen_hdmi_videoinfoframe(encoder, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208254885Sdumbbell 0, 0, 0, 0, 0, 0); 209254885Sdumbbell 210254885Sdumbbell evergreen_hdmi_update_ACR(encoder, mode->clock); 211254885Sdumbbell 212254885Sdumbbell /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ 213254885Sdumbbell WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF); 214254885Sdumbbell WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF); 215254885Sdumbbell WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001); 216254885Sdumbbell WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001); 217254885Sdumbbell} 218