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 */ 26254885Sdumbbell 27254885Sdumbbell#include <sys/cdefs.h> 28254885Sdumbbell__FBSDID("$FreeBSD: releng/11.0/sys/dev/drm2/radeon/r600_hdmi.c 280183 2015-03-17 18:50:33Z dumbbell $"); 29254885Sdumbbell 30254885Sdumbbell#include <dev/drm2/drmP.h> 31254885Sdumbbell#include <dev/drm2/radeon/radeon_drm.h> 32254885Sdumbbell#include "radeon.h" 33254885Sdumbbell#include "radeon_asic.h" 34254885Sdumbbell#include "r600d.h" 35254885Sdumbbell#include "atom.h" 36254885Sdumbbell 37254885Sdumbbell/* 38254885Sdumbbell * HDMI color format 39254885Sdumbbell */ 40254885Sdumbbellenum r600_hdmi_color_format { 41254885Sdumbbell RGB = 0, 42254885Sdumbbell YCC_422 = 1, 43254885Sdumbbell YCC_444 = 2 44254885Sdumbbell}; 45254885Sdumbbell 46254885Sdumbbell/* 47254885Sdumbbell * IEC60958 status bits 48254885Sdumbbell */ 49254885Sdumbbellenum r600_hdmi_iec_status_bits { 50254885Sdumbbell AUDIO_STATUS_DIG_ENABLE = 0x01, 51254885Sdumbbell AUDIO_STATUS_V = 0x02, 52254885Sdumbbell AUDIO_STATUS_VCFG = 0x04, 53254885Sdumbbell AUDIO_STATUS_EMPHASIS = 0x08, 54254885Sdumbbell AUDIO_STATUS_COPYRIGHT = 0x10, 55254885Sdumbbell AUDIO_STATUS_NONAUDIO = 0x20, 56254885Sdumbbell AUDIO_STATUS_PROFESSIONAL = 0x40, 57254885Sdumbbell AUDIO_STATUS_LEVEL = 0x80 58254885Sdumbbell}; 59254885Sdumbbell 60254885Sdumbbellstatic const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = { 61254885Sdumbbell /* 32kHz 44.1kHz 48kHz */ 62254885Sdumbbell /* Clock N CTS N CTS N CTS */ 63254885Sdumbbell { 25174, 4576, 28125, 7007, 31250, 6864, 28125 }, /* 25,20/1.001 MHz */ 64254885Sdumbbell { 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */ 65254885Sdumbbell { 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */ 66254885Sdumbbell { 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */ 67254885Sdumbbell { 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */ 68254885Sdumbbell { 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */ 69254885Sdumbbell { 74175, 11648, 210937, 17836, 234375, 11648, 140625 }, /* 74.25/1.001 MHz */ 70254885Sdumbbell { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */ 71254885Sdumbbell { 148351, 11648, 421875, 8918, 234375, 5824, 140625 }, /* 148.50/1.001 MHz */ 72254885Sdumbbell { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */ 73254885Sdumbbell { 0, 4096, 0, 6272, 0, 6144, 0 } /* Other */ 74254885Sdumbbell}; 75254885Sdumbbell 76254885Sdumbbell/* 77254885Sdumbbell * calculate CTS value if it's not found in the table 78254885Sdumbbell */ 79254885Sdumbbellstatic void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int N, int freq) 80254885Sdumbbell{ 81254885Sdumbbell if (*CTS == 0) 82254885Sdumbbell *CTS = clock * N / (128 * freq) * 1000; 83254885Sdumbbell DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n", 84254885Sdumbbell N, *CTS, freq); 85254885Sdumbbell} 86254885Sdumbbell 87254885Sdumbbellstruct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock) 88254885Sdumbbell{ 89254885Sdumbbell struct radeon_hdmi_acr res; 90254885Sdumbbell u8 i; 91254885Sdumbbell 92254885Sdumbbell for (i = 0; r600_hdmi_predefined_acr[i].clock != clock && 93254885Sdumbbell r600_hdmi_predefined_acr[i].clock != 0; i++) 94254885Sdumbbell ; 95254885Sdumbbell res = r600_hdmi_predefined_acr[i]; 96254885Sdumbbell 97254885Sdumbbell /* In case some CTS are missing */ 98254885Sdumbbell r600_hdmi_calc_cts(clock, &res.cts_32khz, res.n_32khz, 32000); 99254885Sdumbbell r600_hdmi_calc_cts(clock, &res.cts_44_1khz, res.n_44_1khz, 44100); 100254885Sdumbbell r600_hdmi_calc_cts(clock, &res.cts_48khz, res.n_48khz, 48000); 101254885Sdumbbell 102254885Sdumbbell return res; 103254885Sdumbbell} 104254885Sdumbbell 105254885Sdumbbell/* 106254885Sdumbbell * update the N and CTS parameters for a given pixel clock rate 107254885Sdumbbell */ 108254885Sdumbbellstatic void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock) 109254885Sdumbbell{ 110254885Sdumbbell struct drm_device *dev = encoder->dev; 111254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 112254885Sdumbbell struct radeon_hdmi_acr acr = r600_hdmi_acr(clock); 113254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 114254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 115254885Sdumbbell uint32_t offset = dig->afmt->offset; 116254885Sdumbbell 117254885Sdumbbell WREG32(HDMI0_ACR_32_0 + offset, HDMI0_ACR_CTS_32(acr.cts_32khz)); 118254885Sdumbbell WREG32(HDMI0_ACR_32_1 + offset, acr.n_32khz); 119254885Sdumbbell 120254885Sdumbbell WREG32(HDMI0_ACR_44_0 + offset, HDMI0_ACR_CTS_44(acr.cts_44_1khz)); 121254885Sdumbbell WREG32(HDMI0_ACR_44_1 + offset, acr.n_44_1khz); 122254885Sdumbbell 123254885Sdumbbell WREG32(HDMI0_ACR_48_0 + offset, HDMI0_ACR_CTS_48(acr.cts_48khz)); 124254885Sdumbbell WREG32(HDMI0_ACR_48_1 + offset, acr.n_48khz); 125254885Sdumbbell} 126254885Sdumbbell 127254885Sdumbbell/* 128254885Sdumbbell * calculate the crc for a given info frame 129254885Sdumbbell */ 130254885Sdumbbellstatic void r600_hdmi_infoframe_checksum(uint8_t packetType, 131254885Sdumbbell uint8_t versionNumber, 132254885Sdumbbell uint8_t length, 133254885Sdumbbell uint8_t *frame) 134254885Sdumbbell{ 135254885Sdumbbell int i; 136254885Sdumbbell frame[0] = packetType + versionNumber + length; 137254885Sdumbbell for (i = 1; i <= length; i++) 138254885Sdumbbell frame[0] += frame[i]; 139254885Sdumbbell frame[0] = 0x100 - frame[0]; 140254885Sdumbbell} 141254885Sdumbbell 142254885Sdumbbell/* 143254885Sdumbbell * build a HDMI Video Info Frame 144254885Sdumbbell */ 145254885Sdumbbellstatic void r600_hdmi_videoinfoframe( 146254885Sdumbbell struct drm_encoder *encoder, 147254885Sdumbbell enum r600_hdmi_color_format color_format, 148254885Sdumbbell int active_information_present, 149254885Sdumbbell uint8_t active_format_aspect_ratio, 150254885Sdumbbell uint8_t scan_information, 151254885Sdumbbell uint8_t colorimetry, 152254885Sdumbbell uint8_t ex_colorimetry, 153254885Sdumbbell uint8_t quantization, 154254885Sdumbbell int ITC, 155254885Sdumbbell uint8_t picture_aspect_ratio, 156254885Sdumbbell uint8_t video_format_identification, 157254885Sdumbbell uint8_t pixel_repetition, 158254885Sdumbbell uint8_t non_uniform_picture_scaling, 159254885Sdumbbell uint8_t bar_info_data_valid, 160254885Sdumbbell uint16_t top_bar, 161254885Sdumbbell uint16_t bottom_bar, 162254885Sdumbbell uint16_t left_bar, 163254885Sdumbbell uint16_t right_bar 164254885Sdumbbell) 165254885Sdumbbell{ 166254885Sdumbbell struct drm_device *dev = encoder->dev; 167254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 168254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 169254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 170254885Sdumbbell uint32_t offset = dig->afmt->offset; 171254885Sdumbbell 172254885Sdumbbell uint8_t frame[14]; 173254885Sdumbbell 174254885Sdumbbell frame[0x0] = 0; 175254885Sdumbbell frame[0x1] = 176254885Sdumbbell (scan_information & 0x3) | 177254885Sdumbbell ((bar_info_data_valid & 0x3) << 2) | 178254885Sdumbbell ((active_information_present & 0x1) << 4) | 179254885Sdumbbell ((color_format & 0x3) << 5); 180254885Sdumbbell frame[0x2] = 181254885Sdumbbell (active_format_aspect_ratio & 0xF) | 182254885Sdumbbell ((picture_aspect_ratio & 0x3) << 4) | 183254885Sdumbbell ((colorimetry & 0x3) << 6); 184254885Sdumbbell frame[0x3] = 185254885Sdumbbell (non_uniform_picture_scaling & 0x3) | 186254885Sdumbbell ((quantization & 0x3) << 2) | 187254885Sdumbbell ((ex_colorimetry & 0x7) << 4) | 188254885Sdumbbell ((ITC & 0x1) << 7); 189254885Sdumbbell frame[0x4] = (video_format_identification & 0x7F); 190254885Sdumbbell frame[0x5] = (pixel_repetition & 0xF); 191254885Sdumbbell frame[0x6] = (top_bar & 0xFF); 192254885Sdumbbell frame[0x7] = (top_bar >> 8); 193254885Sdumbbell frame[0x8] = (bottom_bar & 0xFF); 194254885Sdumbbell frame[0x9] = (bottom_bar >> 8); 195254885Sdumbbell frame[0xA] = (left_bar & 0xFF); 196254885Sdumbbell frame[0xB] = (left_bar >> 8); 197254885Sdumbbell frame[0xC] = (right_bar & 0xFF); 198254885Sdumbbell frame[0xD] = (right_bar >> 8); 199254885Sdumbbell 200254885Sdumbbell r600_hdmi_infoframe_checksum(0x82, 0x02, 0x0D, frame); 201254885Sdumbbell /* Our header values (type, version, length) should be alright, Intel 202254885Sdumbbell * is using the same. Checksum function also seems to be OK, it works 203254885Sdumbbell * fine for audio infoframe. However calculated value is always lower 204254885Sdumbbell * by 2 in comparison to fglrx. It breaks displaying anything in case 205254885Sdumbbell * of TVs that strictly check the checksum. Hack it manually here to 206254885Sdumbbell * workaround this issue. */ 207254885Sdumbbell frame[0x0] += 2; 208254885Sdumbbell 209254885Sdumbbell WREG32(HDMI0_AVI_INFO0 + offset, 210254885Sdumbbell frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); 211254885Sdumbbell WREG32(HDMI0_AVI_INFO1 + offset, 212254885Sdumbbell frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24)); 213254885Sdumbbell WREG32(HDMI0_AVI_INFO2 + offset, 214254885Sdumbbell frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); 215254885Sdumbbell WREG32(HDMI0_AVI_INFO3 + offset, 216254885Sdumbbell frame[0xC] | (frame[0xD] << 8)); 217254885Sdumbbell} 218254885Sdumbbell 219254885Sdumbbell/* 220254885Sdumbbell * build a Audio Info Frame 221254885Sdumbbell */ 222254885Sdumbbellstatic void r600_hdmi_audioinfoframe( 223254885Sdumbbell struct drm_encoder *encoder, 224254885Sdumbbell uint8_t channel_count, 225254885Sdumbbell uint8_t coding_type, 226254885Sdumbbell uint8_t sample_size, 227254885Sdumbbell uint8_t sample_frequency, 228254885Sdumbbell uint8_t format, 229254885Sdumbbell uint8_t channel_allocation, 230254885Sdumbbell uint8_t level_shift, 231254885Sdumbbell int downmix_inhibit 232254885Sdumbbell) 233254885Sdumbbell{ 234254885Sdumbbell struct drm_device *dev = encoder->dev; 235254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 236254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 237254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 238254885Sdumbbell uint32_t offset = dig->afmt->offset; 239254885Sdumbbell 240254885Sdumbbell uint8_t frame[11]; 241254885Sdumbbell 242254885Sdumbbell frame[0x0] = 0; 243254885Sdumbbell frame[0x1] = (channel_count & 0x7) | ((coding_type & 0xF) << 4); 244254885Sdumbbell frame[0x2] = (sample_size & 0x3) | ((sample_frequency & 0x7) << 2); 245254885Sdumbbell frame[0x3] = format; 246254885Sdumbbell frame[0x4] = channel_allocation; 247254885Sdumbbell frame[0x5] = ((level_shift & 0xF) << 3) | ((downmix_inhibit & 0x1) << 7); 248254885Sdumbbell frame[0x6] = 0; 249254885Sdumbbell frame[0x7] = 0; 250254885Sdumbbell frame[0x8] = 0; 251254885Sdumbbell frame[0x9] = 0; 252254885Sdumbbell frame[0xA] = 0; 253254885Sdumbbell 254254885Sdumbbell r600_hdmi_infoframe_checksum(0x84, 0x01, 0x0A, frame); 255254885Sdumbbell 256254885Sdumbbell WREG32(HDMI0_AUDIO_INFO0 + offset, 257254885Sdumbbell frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); 258254885Sdumbbell WREG32(HDMI0_AUDIO_INFO1 + offset, 259254885Sdumbbell frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x8] << 24)); 260254885Sdumbbell} 261254885Sdumbbell 262254885Sdumbbell/* 263254885Sdumbbell * test if audio buffer is filled enough to start playing 264254885Sdumbbell */ 265254885Sdumbbellstatic bool r600_hdmi_is_audio_buffer_filled(struct drm_encoder *encoder) 266254885Sdumbbell{ 267254885Sdumbbell struct drm_device *dev = encoder->dev; 268254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 269254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 270254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 271254885Sdumbbell uint32_t offset = dig->afmt->offset; 272254885Sdumbbell 273254885Sdumbbell return (RREG32(HDMI0_STATUS + offset) & 0x10) != 0; 274254885Sdumbbell} 275254885Sdumbbell 276254885Sdumbbell/* 277254885Sdumbbell * have buffer status changed since last call? 278254885Sdumbbell */ 279254885Sdumbbellint r600_hdmi_buffer_status_changed(struct drm_encoder *encoder) 280254885Sdumbbell{ 281254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 282254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 283254885Sdumbbell int status, result; 284254885Sdumbbell 285254885Sdumbbell if (!dig->afmt || !dig->afmt->enabled) 286254885Sdumbbell return 0; 287254885Sdumbbell 288254885Sdumbbell status = r600_hdmi_is_audio_buffer_filled(encoder); 289254885Sdumbbell result = dig->afmt->last_buffer_filled_status != status; 290254885Sdumbbell dig->afmt->last_buffer_filled_status = status; 291254885Sdumbbell 292254885Sdumbbell return result; 293254885Sdumbbell} 294254885Sdumbbell 295254885Sdumbbell/* 296254885Sdumbbell * write the audio workaround status to the hardware 297254885Sdumbbell */ 298254885Sdumbbellstatic void r600_hdmi_audio_workaround(struct drm_encoder *encoder) 299254885Sdumbbell{ 300254885Sdumbbell struct drm_device *dev = encoder->dev; 301254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 302254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 303254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 304254885Sdumbbell uint32_t offset = dig->afmt->offset; 305254885Sdumbbell bool hdmi_audio_workaround = false; /* FIXME */ 306254885Sdumbbell u32 value; 307254885Sdumbbell 308254885Sdumbbell if (!hdmi_audio_workaround || 309254885Sdumbbell r600_hdmi_is_audio_buffer_filled(encoder)) 310254885Sdumbbell value = 0; /* disable workaround */ 311254885Sdumbbell else 312254885Sdumbbell value = HDMI0_AUDIO_TEST_EN; /* enable workaround */ 313254885Sdumbbell WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset, 314254885Sdumbbell value, ~HDMI0_AUDIO_TEST_EN); 315254885Sdumbbell} 316254885Sdumbbell 317254885Sdumbbell 318254885Sdumbbell/* 319254885Sdumbbell * update the info frames with the data from the current display mode 320254885Sdumbbell */ 321254885Sdumbbellvoid r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode) 322254885Sdumbbell{ 323254885Sdumbbell struct drm_device *dev = encoder->dev; 324254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 325254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 326254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 327254885Sdumbbell uint32_t offset; 328254885Sdumbbell 329254885Sdumbbell /* Silent, r600_hdmi_enable will raise WARN for us */ 330254885Sdumbbell if (!dig->afmt->enabled) 331254885Sdumbbell return; 332254885Sdumbbell offset = dig->afmt->offset; 333254885Sdumbbell 334254885Sdumbbell r600_audio_set_clock(encoder, mode->clock); 335254885Sdumbbell 336254885Sdumbbell WREG32(HDMI0_VBI_PACKET_CONTROL + offset, 337254885Sdumbbell HDMI0_NULL_SEND); /* send null packets when required */ 338254885Sdumbbell 339254885Sdumbbell WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000); 340254885Sdumbbell 341254885Sdumbbell if (ASIC_IS_DCE32(rdev)) { 342254885Sdumbbell WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, 343254885Sdumbbell HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ 344254885Sdumbbell HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */ 345254885Sdumbbell WREG32(AFMT_AUDIO_PACKET_CONTROL + offset, 346254885Sdumbbell AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */ 347254885Sdumbbell AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ 348254885Sdumbbell } else { 349254885Sdumbbell WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, 350254885Sdumbbell HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */ 351254885Sdumbbell HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */ 352254885Sdumbbell HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */ 353254885Sdumbbell HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */ 354254885Sdumbbell } 355254885Sdumbbell 356254885Sdumbbell WREG32(HDMI0_ACR_PACKET_CONTROL + offset, 357254885Sdumbbell HDMI0_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */ 358254885Sdumbbell HDMI0_ACR_SOURCE); /* select SW CTS value */ 359254885Sdumbbell 360254885Sdumbbell WREG32(HDMI0_VBI_PACKET_CONTROL + offset, 361254885Sdumbbell HDMI0_NULL_SEND | /* send null packets when required */ 362254885Sdumbbell HDMI0_GC_SEND | /* send general control packets */ 363254885Sdumbbell HDMI0_GC_CONT); /* send general control packets every frame */ 364254885Sdumbbell 365254885Sdumbbell /* TODO: HDMI0_AUDIO_INFO_UPDATE */ 366254885Sdumbbell WREG32(HDMI0_INFOFRAME_CONTROL0 + offset, 367254885Sdumbbell HDMI0_AVI_INFO_SEND | /* enable AVI info frames */ 368254885Sdumbbell HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */ 369254885Sdumbbell HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ 370254885Sdumbbell HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */ 371254885Sdumbbell 372254885Sdumbbell WREG32(HDMI0_INFOFRAME_CONTROL1 + offset, 373254885Sdumbbell HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */ 374254885Sdumbbell HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */ 375254885Sdumbbell 376254885Sdumbbell WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */ 377254885Sdumbbell 378254885Sdumbbell r600_hdmi_videoinfoframe(encoder, RGB, 0, 0, 0, 0, 379254885Sdumbbell 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 380254885Sdumbbell 381254885Sdumbbell r600_hdmi_update_ACR(encoder, mode->clock); 382254885Sdumbbell 383254885Sdumbbell /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ 384254885Sdumbbell WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF); 385254885Sdumbbell WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF); 386254885Sdumbbell WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001); 387254885Sdumbbell WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001); 388254885Sdumbbell 389254885Sdumbbell r600_hdmi_audio_workaround(encoder); 390254885Sdumbbell} 391254885Sdumbbell 392254885Sdumbbell/* 393254885Sdumbbell * update settings with current parameters from audio engine 394254885Sdumbbell */ 395254885Sdumbbellvoid r600_hdmi_update_audio_settings(struct drm_encoder *encoder) 396254885Sdumbbell{ 397254885Sdumbbell struct drm_device *dev = encoder->dev; 398254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 399254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 400254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 401254885Sdumbbell struct r600_audio audio = r600_audio_status(rdev); 402254885Sdumbbell uint32_t offset; 403254885Sdumbbell uint32_t iec; 404254885Sdumbbell 405254885Sdumbbell if (!dig->afmt || !dig->afmt->enabled) 406254885Sdumbbell return; 407254885Sdumbbell offset = dig->afmt->offset; 408254885Sdumbbell 409254885Sdumbbell DRM_DEBUG("%s with %d channels, %d Hz sampling rate, %d bits per sample,\n", 410254885Sdumbbell r600_hdmi_is_audio_buffer_filled(encoder) ? "playing" : "stopped", 411254885Sdumbbell audio.channels, audio.rate, audio.bits_per_sample); 412254885Sdumbbell DRM_DEBUG("0x%02X IEC60958 status bits and 0x%02X category code\n", 413254885Sdumbbell (int)audio.status_bits, (int)audio.category_code); 414254885Sdumbbell 415254885Sdumbbell iec = 0; 416254885Sdumbbell if (audio.status_bits & AUDIO_STATUS_PROFESSIONAL) 417254885Sdumbbell iec |= 1 << 0; 418254885Sdumbbell if (audio.status_bits & AUDIO_STATUS_NONAUDIO) 419254885Sdumbbell iec |= 1 << 1; 420254885Sdumbbell if (audio.status_bits & AUDIO_STATUS_COPYRIGHT) 421254885Sdumbbell iec |= 1 << 2; 422254885Sdumbbell if (audio.status_bits & AUDIO_STATUS_EMPHASIS) 423254885Sdumbbell iec |= 1 << 3; 424254885Sdumbbell 425254885Sdumbbell iec |= HDMI0_60958_CS_CATEGORY_CODE(audio.category_code); 426254885Sdumbbell 427254885Sdumbbell switch (audio.rate) { 428254885Sdumbbell case 32000: 429254885Sdumbbell iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x3); 430254885Sdumbbell break; 431254885Sdumbbell case 44100: 432254885Sdumbbell iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x0); 433254885Sdumbbell break; 434254885Sdumbbell case 48000: 435254885Sdumbbell iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x2); 436254885Sdumbbell break; 437254885Sdumbbell case 88200: 438254885Sdumbbell iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x8); 439254885Sdumbbell break; 440254885Sdumbbell case 96000: 441254885Sdumbbell iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xa); 442254885Sdumbbell break; 443254885Sdumbbell case 176400: 444254885Sdumbbell iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xc); 445254885Sdumbbell break; 446254885Sdumbbell case 192000: 447254885Sdumbbell iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xe); 448254885Sdumbbell break; 449254885Sdumbbell } 450254885Sdumbbell 451254885Sdumbbell WREG32(HDMI0_60958_0 + offset, iec); 452254885Sdumbbell 453254885Sdumbbell iec = 0; 454254885Sdumbbell switch (audio.bits_per_sample) { 455254885Sdumbbell case 16: 456254885Sdumbbell iec |= HDMI0_60958_CS_WORD_LENGTH(0x2); 457254885Sdumbbell break; 458254885Sdumbbell case 20: 459254885Sdumbbell iec |= HDMI0_60958_CS_WORD_LENGTH(0x3); 460254885Sdumbbell break; 461254885Sdumbbell case 24: 462254885Sdumbbell iec |= HDMI0_60958_CS_WORD_LENGTH(0xb); 463254885Sdumbbell break; 464254885Sdumbbell } 465254885Sdumbbell if (audio.status_bits & AUDIO_STATUS_V) 466254885Sdumbbell iec |= 0x5 << 16; 467254885Sdumbbell WREG32_P(HDMI0_60958_1 + offset, iec, ~0x5000f); 468254885Sdumbbell 469254885Sdumbbell r600_hdmi_audioinfoframe(encoder, audio.channels - 1, 0, 0, 0, 0, 0, 0, 470254885Sdumbbell 0); 471254885Sdumbbell 472254885Sdumbbell r600_hdmi_audio_workaround(encoder); 473254885Sdumbbell} 474254885Sdumbbell 475254885Sdumbbell/* 476254885Sdumbbell * enable the HDMI engine 477254885Sdumbbell */ 478254885Sdumbbellvoid r600_hdmi_enable(struct drm_encoder *encoder) 479254885Sdumbbell{ 480254885Sdumbbell struct drm_device *dev = encoder->dev; 481254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 482254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 483254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 484254885Sdumbbell uint32_t offset; 485254885Sdumbbell u32 hdmi; 486254885Sdumbbell 487254885Sdumbbell if (ASIC_IS_DCE6(rdev)) 488254885Sdumbbell return; 489254885Sdumbbell 490254885Sdumbbell /* Silent, r600_hdmi_enable will raise WARN for us */ 491254885Sdumbbell if (dig->afmt->enabled) 492254885Sdumbbell return; 493254885Sdumbbell offset = dig->afmt->offset; 494254885Sdumbbell 495254885Sdumbbell /* Older chipsets require setting HDMI and routing manually */ 496280183Sdumbbell if (ASIC_IS_DCE2(rdev) && !ASIC_IS_DCE3(rdev)) { 497254885Sdumbbell hdmi = HDMI0_ERROR_ACK | HDMI0_ENABLE; 498254885Sdumbbell switch (radeon_encoder->encoder_id) { 499254885Sdumbbell case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 500254885Sdumbbell WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN, 501254885Sdumbbell ~AVIVO_TMDSA_CNTL_HDMI_EN); 502254885Sdumbbell hdmi |= HDMI0_STREAM(HDMI0_STREAM_TMDSA); 503254885Sdumbbell break; 504254885Sdumbbell case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 505254885Sdumbbell WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN, 506254885Sdumbbell ~AVIVO_LVTMA_CNTL_HDMI_EN); 507254885Sdumbbell hdmi |= HDMI0_STREAM(HDMI0_STREAM_LVTMA); 508254885Sdumbbell break; 509254885Sdumbbell case ENCODER_OBJECT_ID_INTERNAL_DDI: 510254885Sdumbbell WREG32_P(DDIA_CNTL, DDIA_HDMI_EN, ~DDIA_HDMI_EN); 511254885Sdumbbell hdmi |= HDMI0_STREAM(HDMI0_STREAM_DDIA); 512254885Sdumbbell break; 513254885Sdumbbell case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 514254885Sdumbbell hdmi |= HDMI0_STREAM(HDMI0_STREAM_DVOA); 515254885Sdumbbell break; 516254885Sdumbbell default: 517254885Sdumbbell dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", 518254885Sdumbbell radeon_encoder->encoder_id); 519254885Sdumbbell break; 520254885Sdumbbell } 521254885Sdumbbell WREG32(HDMI0_CONTROL + offset, hdmi); 522254885Sdumbbell } 523254885Sdumbbell 524254885Sdumbbell if (rdev->irq.installed) { 525254885Sdumbbell /* if irq is available use it */ 526254885Sdumbbell radeon_irq_kms_enable_afmt(rdev, dig->afmt->id); 527254885Sdumbbell } 528254885Sdumbbell 529254885Sdumbbell dig->afmt->enabled = true; 530254885Sdumbbell 531254885Sdumbbell DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", 532254885Sdumbbell offset, radeon_encoder->encoder_id); 533254885Sdumbbell} 534254885Sdumbbell 535254885Sdumbbell/* 536254885Sdumbbell * disable the HDMI engine 537254885Sdumbbell */ 538254885Sdumbbellvoid r600_hdmi_disable(struct drm_encoder *encoder) 539254885Sdumbbell{ 540254885Sdumbbell struct drm_device *dev = encoder->dev; 541254885Sdumbbell struct radeon_device *rdev = dev->dev_private; 542254885Sdumbbell struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 543254885Sdumbbell struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 544254885Sdumbbell uint32_t offset; 545254885Sdumbbell 546254885Sdumbbell if (ASIC_IS_DCE6(rdev)) 547254885Sdumbbell return; 548254885Sdumbbell 549254885Sdumbbell /* Called for ATOM_ENCODER_MODE_HDMI only */ 550254885Sdumbbell if (!dig || !dig->afmt) { 551254885Sdumbbell return; 552254885Sdumbbell } 553254885Sdumbbell if (!dig->afmt->enabled) 554254885Sdumbbell return; 555254885Sdumbbell offset = dig->afmt->offset; 556254885Sdumbbell 557254885Sdumbbell DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n", 558254885Sdumbbell offset, radeon_encoder->encoder_id); 559254885Sdumbbell 560254885Sdumbbell /* disable irq */ 561254885Sdumbbell radeon_irq_kms_disable_afmt(rdev, dig->afmt->id); 562254885Sdumbbell 563254885Sdumbbell /* Older chipsets not handled by AtomBIOS */ 564280183Sdumbbell if (ASIC_IS_DCE2(rdev) && !ASIC_IS_DCE3(rdev)) { 565254885Sdumbbell switch (radeon_encoder->encoder_id) { 566254885Sdumbbell case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: 567254885Sdumbbell WREG32_P(AVIVO_TMDSA_CNTL, 0, 568254885Sdumbbell ~AVIVO_TMDSA_CNTL_HDMI_EN); 569254885Sdumbbell break; 570254885Sdumbbell case ENCODER_OBJECT_ID_INTERNAL_LVTM1: 571254885Sdumbbell WREG32_P(AVIVO_LVTMA_CNTL, 0, 572254885Sdumbbell ~AVIVO_LVTMA_CNTL_HDMI_EN); 573254885Sdumbbell break; 574254885Sdumbbell case ENCODER_OBJECT_ID_INTERNAL_DDI: 575254885Sdumbbell WREG32_P(DDIA_CNTL, 0, ~DDIA_HDMI_EN); 576254885Sdumbbell break; 577254885Sdumbbell case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 578254885Sdumbbell break; 579254885Sdumbbell default: 580254885Sdumbbell dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n", 581254885Sdumbbell radeon_encoder->encoder_id); 582254885Sdumbbell break; 583254885Sdumbbell } 584254885Sdumbbell WREG32(HDMI0_CONTROL + offset, HDMI0_ERROR_ACK); 585254885Sdumbbell } 586254885Sdumbbell 587254885Sdumbbell dig->afmt->enabled = false; 588254885Sdumbbell} 589