| 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* |
| 3 | * ATI/AMD codec support |
| 4 | */ |
| 5 | |
| 6 | #include <linux/init.h> |
| 7 | #include <linux/slab.h> |
| 8 | #include <linux/module.h> |
| 9 | #include <linux/unaligned.h> |
| 10 | #include <sound/core.h> |
| 11 | #include <sound/tlv.h> |
| 12 | #include <sound/hdaudio.h> |
| 13 | #include <sound/hda_codec.h> |
| 14 | #include "hda_local.h" |
| 15 | #include "hdmi_local.h" |
| 16 | |
| 17 | #define is_amdhdmi_rev3_or_later(codec) \ |
| 18 | ((codec)->core.vendor_id == 0x1002aa01 && \ |
| 19 | ((codec)->core.revision_id & 0xff00) >= 0x0300) |
| 20 | #define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec) |
| 21 | |
| 22 | /* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */ |
| 23 | #define ATI_VERB_SET_CHANNEL_ALLOCATION 0x771 |
| 24 | #define ATI_VERB_SET_DOWNMIX_INFO 0x772 |
| 25 | #define ATI_VERB_SET_MULTICHANNEL_01 0x777 |
| 26 | #define ATI_VERB_SET_MULTICHANNEL_23 0x778 |
| 27 | #define ATI_VERB_SET_MULTICHANNEL_45 0x779 |
| 28 | #define ATI_VERB_SET_MULTICHANNEL_67 0x77a |
| 29 | #define ATI_VERB_SET_HBR_CONTROL 0x77c |
| 30 | #define ATI_VERB_SET_MULTICHANNEL_1 0x785 |
| 31 | #define ATI_VERB_SET_MULTICHANNEL_3 0x786 |
| 32 | #define ATI_VERB_SET_MULTICHANNEL_5 0x787 |
| 33 | #define ATI_VERB_SET_MULTICHANNEL_7 0x788 |
| 34 | #define ATI_VERB_SET_MULTICHANNEL_MODE 0x789 |
| 35 | #define ATI_VERB_GET_CHANNEL_ALLOCATION 0xf71 |
| 36 | #define ATI_VERB_GET_DOWNMIX_INFO 0xf72 |
| 37 | #define ATI_VERB_GET_MULTICHANNEL_01 0xf77 |
| 38 | #define ATI_VERB_GET_MULTICHANNEL_23 0xf78 |
| 39 | #define ATI_VERB_GET_MULTICHANNEL_45 0xf79 |
| 40 | #define ATI_VERB_GET_MULTICHANNEL_67 0xf7a |
| 41 | #define ATI_VERB_GET_HBR_CONTROL 0xf7c |
| 42 | #define ATI_VERB_GET_MULTICHANNEL_1 0xf85 |
| 43 | #define ATI_VERB_GET_MULTICHANNEL_3 0xf86 |
| 44 | #define ATI_VERB_GET_MULTICHANNEL_5 0xf87 |
| 45 | #define ATI_VERB_GET_MULTICHANNEL_7 0xf88 |
| 46 | #define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89 |
| 47 | |
| 48 | /* AMD specific HDA cvt verbs */ |
| 49 | #define ATI_VERB_SET_RAMP_RATE 0x770 |
| 50 | #define ATI_VERB_GET_RAMP_RATE 0xf70 |
| 51 | |
| 52 | #define ATI_OUT_ENABLE 0x1 |
| 53 | |
| 54 | #define ATI_MULTICHANNEL_MODE_PAIRED 0 |
| 55 | #define ATI_MULTICHANNEL_MODE_SINGLE 1 |
| 56 | |
| 57 | #define ATI_HBR_CAPABLE 0x01 |
| 58 | #define ATI_HBR_ENABLE 0x10 |
| 59 | |
| 60 | /* ATI/AMD specific ELD emulation */ |
| 61 | |
| 62 | #define ATI_VERB_SET_AUDIO_DESCRIPTOR 0x776 |
| 63 | #define ATI_VERB_SET_SINK_INFO_INDEX 0x780 |
| 64 | #define ATI_VERB_GET_SPEAKER_ALLOCATION 0xf70 |
| 65 | #define ATI_VERB_GET_AUDIO_DESCRIPTOR 0xf76 |
| 66 | #define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b |
| 67 | #define ATI_VERB_GET_SINK_INFO_INDEX 0xf80 |
| 68 | #define ATI_VERB_GET_SINK_INFO_DATA 0xf81 |
| 69 | |
| 70 | #define ATI_SPKALLOC_SPKALLOC 0x007f |
| 71 | #define ATI_SPKALLOC_TYPE_HDMI 0x0100 |
| 72 | #define ATI_SPKALLOC_TYPE_DISPLAYPORT 0x0200 |
| 73 | |
| 74 | /* first three bytes are just standard SAD */ |
| 75 | #define ATI_AUDIODESC_CHANNELS 0x00000007 |
| 76 | #define ATI_AUDIODESC_RATES 0x0000ff00 |
| 77 | #define ATI_AUDIODESC_LPCM_STEREO_RATES 0xff000000 |
| 78 | |
| 79 | /* in standard HDMI VSDB format */ |
| 80 | #define ATI_DELAY_VIDEO_LATENCY 0x000000ff |
| 81 | #define ATI_DELAY_AUDIO_LATENCY 0x0000ff00 |
| 82 | |
| 83 | enum ati_sink_info_idx { |
| 84 | ATI_INFO_IDX_MANUFACTURER_ID = 0, |
| 85 | ATI_INFO_IDX_PRODUCT_ID = 1, |
| 86 | ATI_INFO_IDX_SINK_DESC_LEN = 2, |
| 87 | ATI_INFO_IDX_PORT_ID_LOW = 3, |
| 88 | ATI_INFO_IDX_PORT_ID_HIGH = 4, |
| 89 | ATI_INFO_IDX_SINK_DESC_FIRST = 5, |
| 90 | ATI_INFO_IDX_SINK_DESC_LAST = 22, /* max len 18 bytes */ |
| 91 | }; |
| 92 | |
| 93 | static int get_eld_ati(struct hda_codec *codec, hda_nid_t nid, |
| 94 | unsigned char *buf, int *eld_size, bool rev3_or_later) |
| 95 | { |
| 96 | int spkalloc, ati_sad, aud_synch; |
| 97 | int sink_desc_len = 0; |
| 98 | int pos, i; |
| 99 | |
| 100 | /* ATI/AMD does not have ELD, emulate it */ |
| 101 | |
| 102 | spkalloc = snd_hda_codec_read(codec, nid, flags: 0, ATI_VERB_GET_SPEAKER_ALLOCATION, parm: 0); |
| 103 | |
| 104 | if (spkalloc <= 0) { |
| 105 | codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n" ); |
| 106 | return -EINVAL; |
| 107 | } |
| 108 | |
| 109 | memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3); |
| 110 | |
| 111 | /* version */ |
| 112 | buf[0] = ELD_VER_CEA_861D << 3; |
| 113 | |
| 114 | /* speaker allocation from EDID */ |
| 115 | buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC; |
| 116 | |
| 117 | /* is DisplayPort? */ |
| 118 | if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT) |
| 119 | buf[5] |= 0x04; |
| 120 | |
| 121 | pos = ELD_FIXED_BYTES; |
| 122 | |
| 123 | if (rev3_or_later) { |
| 124 | int sink_info; |
| 125 | |
| 126 | snd_hda_codec_write(codec, nid, flags: 0, ATI_VERB_SET_SINK_INFO_INDEX, parm: ATI_INFO_IDX_PORT_ID_LOW); |
| 127 | sink_info = snd_hda_codec_read(codec, nid, flags: 0, ATI_VERB_GET_SINK_INFO_DATA, parm: 0); |
| 128 | put_unaligned_le32(val: sink_info, p: buf + 8); |
| 129 | |
| 130 | snd_hda_codec_write(codec, nid, flags: 0, ATI_VERB_SET_SINK_INFO_INDEX, parm: ATI_INFO_IDX_PORT_ID_HIGH); |
| 131 | sink_info = snd_hda_codec_read(codec, nid, flags: 0, ATI_VERB_GET_SINK_INFO_DATA, parm: 0); |
| 132 | put_unaligned_le32(val: sink_info, p: buf + 12); |
| 133 | |
| 134 | snd_hda_codec_write(codec, nid, flags: 0, ATI_VERB_SET_SINK_INFO_INDEX, parm: ATI_INFO_IDX_MANUFACTURER_ID); |
| 135 | sink_info = snd_hda_codec_read(codec, nid, flags: 0, ATI_VERB_GET_SINK_INFO_DATA, parm: 0); |
| 136 | put_unaligned_le16(val: sink_info, p: buf + 16); |
| 137 | |
| 138 | snd_hda_codec_write(codec, nid, flags: 0, ATI_VERB_SET_SINK_INFO_INDEX, parm: ATI_INFO_IDX_PRODUCT_ID); |
| 139 | sink_info = snd_hda_codec_read(codec, nid, flags: 0, ATI_VERB_GET_SINK_INFO_DATA, parm: 0); |
| 140 | put_unaligned_le16(val: sink_info, p: buf + 18); |
| 141 | |
| 142 | snd_hda_codec_write(codec, nid, flags: 0, ATI_VERB_SET_SINK_INFO_INDEX, parm: ATI_INFO_IDX_SINK_DESC_LEN); |
| 143 | sink_desc_len = snd_hda_codec_read(codec, nid, flags: 0, ATI_VERB_GET_SINK_INFO_DATA, parm: 0); |
| 144 | |
| 145 | if (sink_desc_len > ELD_MAX_MNL) { |
| 146 | codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n" , |
| 147 | sink_desc_len); |
| 148 | sink_desc_len = ELD_MAX_MNL; |
| 149 | } |
| 150 | |
| 151 | buf[4] |= sink_desc_len; |
| 152 | |
| 153 | for (i = 0; i < sink_desc_len; i++) { |
| 154 | snd_hda_codec_write(codec, nid, flags: 0, ATI_VERB_SET_SINK_INFO_INDEX, parm: ATI_INFO_IDX_SINK_DESC_FIRST + i); |
| 155 | buf[pos++] = snd_hda_codec_read(codec, nid, flags: 0, ATI_VERB_GET_SINK_INFO_DATA, parm: 0); |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) { |
| 160 | if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST) |
| 161 | continue; /* not handled by ATI/AMD */ |
| 162 | |
| 163 | snd_hda_codec_write(codec, nid, flags: 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, parm: i << 3); |
| 164 | ati_sad = snd_hda_codec_read(codec, nid, flags: 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, parm: 0); |
| 165 | |
| 166 | if (ati_sad <= 0) |
| 167 | continue; |
| 168 | |
| 169 | if (ati_sad & ATI_AUDIODESC_RATES) { |
| 170 | /* format is supported, copy SAD as-is */ |
| 171 | buf[pos++] = (ati_sad & 0x0000ff) >> 0; |
| 172 | buf[pos++] = (ati_sad & 0x00ff00) >> 8; |
| 173 | buf[pos++] = (ati_sad & 0xff0000) >> 16; |
| 174 | } |
| 175 | |
| 176 | if (i == AUDIO_CODING_TYPE_LPCM |
| 177 | && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) |
| 178 | && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) { |
| 179 | /* for PCM there is a separate stereo rate mask */ |
| 180 | buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1; |
| 181 | /* rates from the extra byte */ |
| 182 | buf[pos++] = (ati_sad & 0xff000000) >> 24; |
| 183 | buf[pos++] = (ati_sad & 0x00ff0000) >> 16; |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | if (pos == ELD_FIXED_BYTES + sink_desc_len) { |
| 188 | codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n" ); |
| 189 | return -EINVAL; |
| 190 | } |
| 191 | |
| 192 | /* |
| 193 | * HDMI VSDB latency format: |
| 194 | * separately for both audio and video: |
| 195 | * 0 field not valid or unknown latency |
| 196 | * [1..251] msecs = (x-1)*2 (max 500ms with x = 251 = 0xfb) |
| 197 | * 255 audio/video not supported |
| 198 | * |
| 199 | * HDA latency format: |
| 200 | * single value indicating video latency relative to audio: |
| 201 | * 0 unknown or 0ms |
| 202 | * [1..250] msecs = x*2 (max 500ms with x = 250 = 0xfa) |
| 203 | * [251..255] reserved |
| 204 | */ |
| 205 | aud_synch = snd_hda_codec_read(codec, nid, flags: 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, parm: 0); |
| 206 | if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) { |
| 207 | int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY); |
| 208 | int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8; |
| 209 | |
| 210 | if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb && |
| 211 | video_latency_hdmi > audio_latency_hdmi) |
| 212 | buf[6] = video_latency_hdmi - audio_latency_hdmi; |
| 213 | /* else unknown/invalid or 0ms or video ahead of audio, so use zero */ |
| 214 | } |
| 215 | |
| 216 | /* SAD count */ |
| 217 | buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4; |
| 218 | |
| 219 | /* Baseline ELD block length is 4-byte aligned */ |
| 220 | pos = round_up(pos, 4); |
| 221 | |
| 222 | /* Baseline ELD length (4-byte header is not counted in) */ |
| 223 | buf[2] = (pos - 4) / 4; |
| 224 | |
| 225 | *eld_size = pos; |
| 226 | |
| 227 | return 0; |
| 228 | } |
| 229 | |
| 230 | static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid, |
| 231 | int dev_id, unsigned char *buf, int *eld_size) |
| 232 | { |
| 233 | WARN_ON(dev_id != 0); |
| 234 | /* call hda_eld.c ATI/AMD-specific function */ |
| 235 | return get_eld_ati(codec, nid, buf, eld_size, |
| 236 | is_amdhdmi_rev3_or_later(codec)); |
| 237 | } |
| 238 | |
| 239 | static void atihdmi_pin_setup_infoframe(struct hda_codec *codec, |
| 240 | hda_nid_t pin_nid, int dev_id, int ca, |
| 241 | int active_channels, int conn_type) |
| 242 | { |
| 243 | WARN_ON(dev_id != 0); |
| 244 | snd_hda_codec_write(codec, nid: pin_nid, flags: 0, ATI_VERB_SET_CHANNEL_ALLOCATION, parm: ca); |
| 245 | } |
| 246 | |
| 247 | static int atihdmi_paired_swap_fc_lfe(int pos) |
| 248 | { |
| 249 | /* |
| 250 | * ATI/AMD have automatic FC/LFE swap built-in |
| 251 | * when in pairwise mapping mode. |
| 252 | */ |
| 253 | |
| 254 | switch (pos) { |
| 255 | /* see channel_allocations[].speakers[] */ |
| 256 | case 2: return 3; |
| 257 | case 3: return 2; |
| 258 | default: return pos; |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap, |
| 263 | int ca, int chs, unsigned char *map) |
| 264 | { |
| 265 | struct hdac_cea_channel_speaker_allocation *cap; |
| 266 | int i, j; |
| 267 | |
| 268 | /* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */ |
| 269 | |
| 270 | cap = snd_hdac_get_ch_alloc_from_ca(ca); |
| 271 | for (i = 0; i < chs; ++i) { |
| 272 | int mask = snd_hdac_chmap_to_spk_mask(c: map[i]); |
| 273 | bool ok = false; |
| 274 | bool companion_ok = false; |
| 275 | |
| 276 | if (!mask) |
| 277 | continue; |
| 278 | |
| 279 | for (j = 0 + i % 2; j < 8; j += 2) { |
| 280 | int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(pos: j); |
| 281 | |
| 282 | if (cap->speakers[chan_idx] == mask) { |
| 283 | /* channel is in a supported position */ |
| 284 | ok = true; |
| 285 | |
| 286 | if (i % 2 == 0 && i + 1 < chs) { |
| 287 | /* even channel, check the odd companion */ |
| 288 | int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(pos: j + 1); |
| 289 | int comp_mask_req = snd_hdac_chmap_to_spk_mask(c: map[i+1]); |
| 290 | int comp_mask_act = cap->speakers[comp_chan_idx]; |
| 291 | |
| 292 | if (comp_mask_req == comp_mask_act) |
| 293 | companion_ok = true; |
| 294 | else |
| 295 | return -EINVAL; |
| 296 | } |
| 297 | break; |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | if (!ok) |
| 302 | return -EINVAL; |
| 303 | |
| 304 | if (companion_ok) |
| 305 | i++; /* companion channel already checked */ |
| 306 | } |
| 307 | |
| 308 | return 0; |
| 309 | } |
| 310 | |
| 311 | static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac, |
| 312 | hda_nid_t pin_nid, int hdmi_slot, int stream_channel) |
| 313 | { |
| 314 | struct hda_codec *codec = hdac_to_hda_codec(hdac); |
| 315 | int verb; |
| 316 | int ati_channel_setup = 0; |
| 317 | |
| 318 | if (hdmi_slot > 7) |
| 319 | return -EINVAL; |
| 320 | |
| 321 | if (!has_amd_full_remap_support(codec)) { |
| 322 | hdmi_slot = atihdmi_paired_swap_fc_lfe(pos: hdmi_slot); |
| 323 | |
| 324 | /* In case this is an odd slot but without stream channel, do not |
| 325 | * disable the slot since the corresponding even slot could have a |
| 326 | * channel. In case neither have a channel, the slot pair will be |
| 327 | * disabled when this function is called for the even slot. |
| 328 | */ |
| 329 | if (hdmi_slot % 2 != 0 && stream_channel == 0xf) |
| 330 | return 0; |
| 331 | |
| 332 | hdmi_slot -= hdmi_slot % 2; |
| 333 | |
| 334 | if (stream_channel != 0xf) |
| 335 | stream_channel -= stream_channel % 2; |
| 336 | } |
| 337 | |
| 338 | verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e; |
| 339 | |
| 340 | /* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */ |
| 341 | |
| 342 | if (stream_channel != 0xf) |
| 343 | ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE; |
| 344 | |
| 345 | return snd_hda_codec_write(codec, nid: pin_nid, flags: 0, verb, parm: ati_channel_setup); |
| 346 | } |
| 347 | |
| 348 | static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac, |
| 349 | hda_nid_t pin_nid, int asp_slot) |
| 350 | { |
| 351 | struct hda_codec *codec = hdac_to_hda_codec(hdac); |
| 352 | bool was_odd = false; |
| 353 | int ati_asp_slot = asp_slot; |
| 354 | int verb; |
| 355 | int ati_channel_setup; |
| 356 | |
| 357 | if (asp_slot > 7) |
| 358 | return -EINVAL; |
| 359 | |
| 360 | if (!has_amd_full_remap_support(codec)) { |
| 361 | ati_asp_slot = atihdmi_paired_swap_fc_lfe(pos: asp_slot); |
| 362 | if (ati_asp_slot % 2 != 0) { |
| 363 | ati_asp_slot -= 1; |
| 364 | was_odd = true; |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e; |
| 369 | |
| 370 | ati_channel_setup = snd_hda_codec_read(codec, nid: pin_nid, flags: 0, verb, parm: 0); |
| 371 | |
| 372 | if (!(ati_channel_setup & ATI_OUT_ENABLE)) |
| 373 | return 0xf; |
| 374 | |
| 375 | return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd; |
| 376 | } |
| 377 | |
| 378 | static int atihdmi_paired_chmap_cea_alloc_validate_get_type( |
| 379 | struct hdac_chmap *chmap, |
| 380 | struct hdac_cea_channel_speaker_allocation *cap, |
| 381 | int channels) |
| 382 | { |
| 383 | int c; |
| 384 | |
| 385 | /* |
| 386 | * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so |
| 387 | * we need to take that into account (a single channel may take 2 |
| 388 | * channel slots if we need to carry a silent channel next to it). |
| 389 | * On Rev3+ AMD codecs this function is not used. |
| 390 | */ |
| 391 | int chanpairs = 0; |
| 392 | |
| 393 | /* We only produce even-numbered channel count TLVs */ |
| 394 | if ((channels % 2) != 0) |
| 395 | return -1; |
| 396 | |
| 397 | for (c = 0; c < 7; c += 2) { |
| 398 | if (cap->speakers[c] || cap->speakers[c+1]) |
| 399 | chanpairs++; |
| 400 | } |
| 401 | |
| 402 | if (chanpairs * 2 != channels) |
| 403 | return -1; |
| 404 | |
| 405 | return SNDRV_CTL_TLVT_CHMAP_PAIRED; |
| 406 | } |
| 407 | |
| 408 | static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, |
| 409 | struct hdac_cea_channel_speaker_allocation *cap, |
| 410 | unsigned int *chmap, int channels) |
| 411 | { |
| 412 | /* produce paired maps for pre-rev3 ATI/AMD codecs */ |
| 413 | int count = 0; |
| 414 | int c; |
| 415 | |
| 416 | for (c = 7; c >= 0; c--) { |
| 417 | int chan = 7 - atihdmi_paired_swap_fc_lfe(pos: 7 - c); |
| 418 | int spk = cap->speakers[chan]; |
| 419 | |
| 420 | if (!spk) { |
| 421 | /* add N/A channel if the companion channel is occupied */ |
| 422 | if (cap->speakers[chan + (chan % 2 ? -1 : 1)]) |
| 423 | chmap[count++] = SNDRV_CHMAP_NA; |
| 424 | |
| 425 | continue; |
| 426 | } |
| 427 | |
| 428 | chmap[count++] = snd_hdac_spk_to_chmap(spk); |
| 429 | } |
| 430 | |
| 431 | WARN_ON(count != channels); |
| 432 | } |
| 433 | |
| 434 | static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, |
| 435 | int dev_id, bool hbr) |
| 436 | { |
| 437 | int hbr_ctl, hbr_ctl_new; |
| 438 | |
| 439 | WARN_ON(dev_id != 0); |
| 440 | |
| 441 | hbr_ctl = snd_hda_codec_read(codec, nid: pin_nid, flags: 0, ATI_VERB_GET_HBR_CONTROL, parm: 0); |
| 442 | if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) { |
| 443 | if (hbr) |
| 444 | hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE; |
| 445 | else |
| 446 | hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE; |
| 447 | |
| 448 | codec_dbg(codec, |
| 449 | "%s: NID=0x%x, %shbr-ctl=0x%x\n" , |
| 450 | __func__, |
| 451 | pin_nid, |
| 452 | hbr_ctl == hbr_ctl_new ? "" : "new-" , |
| 453 | hbr_ctl_new); |
| 454 | |
| 455 | if (hbr_ctl != hbr_ctl_new) |
| 456 | snd_hda_codec_write(codec, nid: pin_nid, flags: 0, |
| 457 | ATI_VERB_SET_HBR_CONTROL, |
| 458 | parm: hbr_ctl_new); |
| 459 | |
| 460 | } else if (hbr) |
| 461 | return -EINVAL; |
| 462 | |
| 463 | return 0; |
| 464 | } |
| 465 | |
| 466 | static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, |
| 467 | hda_nid_t pin_nid, int dev_id, |
| 468 | u32 stream_tag, int format) |
| 469 | { |
| 470 | if (is_amdhdmi_rev3_or_later(codec)) { |
| 471 | int ramp_rate = 180; /* default as per AMD spec */ |
| 472 | /* disable ramp-up/down for non-pcm as per AMD spec */ |
| 473 | if (format & AC_FMT_TYPE_NON_PCM) |
| 474 | ramp_rate = 0; |
| 475 | |
| 476 | snd_hda_codec_write(codec, nid: cvt_nid, flags: 0, ATI_VERB_SET_RAMP_RATE, parm: ramp_rate); |
| 477 | } |
| 478 | |
| 479 | return snd_hda_hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id, |
| 480 | stream_tag, format); |
| 481 | } |
| 482 | |
| 483 | |
| 484 | static int atihdmi_init(struct hda_codec *codec) |
| 485 | { |
| 486 | struct hdmi_spec *spec = codec->spec; |
| 487 | int pin_idx, err; |
| 488 | |
| 489 | err = snd_hda_hdmi_generic_init(codec); |
| 490 | |
| 491 | if (err) |
| 492 | return err; |
| 493 | |
| 494 | for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { |
| 495 | struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); |
| 496 | |
| 497 | /* make sure downmix information in infoframe is zero */ |
| 498 | snd_hda_codec_write(codec, nid: per_pin->pin_nid, flags: 0, ATI_VERB_SET_DOWNMIX_INFO, parm: 0); |
| 499 | |
| 500 | /* enable channel-wise remap mode if supported */ |
| 501 | if (has_amd_full_remap_support(codec)) |
| 502 | snd_hda_codec_write(codec, nid: per_pin->pin_nid, flags: 0, |
| 503 | ATI_VERB_SET_MULTICHANNEL_MODE, |
| 504 | ATI_MULTICHANNEL_MODE_SINGLE); |
| 505 | } |
| 506 | codec->auto_runtime_pm = 1; |
| 507 | |
| 508 | return 0; |
| 509 | } |
| 510 | |
| 511 | /* map from pin NID to port; port is 0-based */ |
| 512 | /* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */ |
| 513 | static int atihdmi_pin2port(void *audio_ptr, int pin_nid) |
| 514 | { |
| 515 | return pin_nid / 2 - 1; |
| 516 | } |
| 517 | |
| 518 | /* reverse-map from port to pin NID: see above */ |
| 519 | static int atihdmi_port2pin(struct hda_codec *codec, int port) |
| 520 | { |
| 521 | return port * 2 + 3; |
| 522 | } |
| 523 | |
| 524 | static const struct drm_audio_component_audio_ops atihdmi_audio_ops = { |
| 525 | .pin2port = atihdmi_pin2port, |
| 526 | .pin_eld_notify = snd_hda_hdmi_acomp_pin_eld_notify, |
| 527 | .master_bind = snd_hda_hdmi_acomp_master_bind, |
| 528 | .master_unbind = snd_hda_hdmi_acomp_master_unbind, |
| 529 | }; |
| 530 | |
| 531 | static int atihdmi_probe(struct hda_codec *codec, const struct hda_device_id *id) |
| 532 | { |
| 533 | struct hdmi_spec *spec; |
| 534 | struct hdmi_spec_per_cvt *per_cvt; |
| 535 | int err, cvt_idx; |
| 536 | |
| 537 | err = snd_hda_hdmi_generic_probe(codec); |
| 538 | if (err) |
| 539 | return err; |
| 540 | |
| 541 | spec = codec->spec; |
| 542 | |
| 543 | spec->static_pcm_mapping = true; |
| 544 | |
| 545 | spec->ops.pin_get_eld = atihdmi_pin_get_eld; |
| 546 | spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe; |
| 547 | spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup; |
| 548 | spec->ops.setup_stream = atihdmi_setup_stream; |
| 549 | |
| 550 | spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel; |
| 551 | spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel; |
| 552 | |
| 553 | if (!has_amd_full_remap_support(codec)) { |
| 554 | /* override to ATI/AMD-specific versions with pairwise mapping */ |
| 555 | spec->chmap.ops.chmap_cea_alloc_validate_get_type = |
| 556 | atihdmi_paired_chmap_cea_alloc_validate_get_type; |
| 557 | spec->chmap.ops.cea_alloc_to_tlv_chmap = |
| 558 | atihdmi_paired_cea_alloc_to_tlv_chmap; |
| 559 | spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate; |
| 560 | } |
| 561 | |
| 562 | /* ATI/AMD converters do not advertise all of their capabilities */ |
| 563 | for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { |
| 564 | per_cvt = get_cvt(spec, cvt_idx); |
| 565 | per_cvt->channels_max = max(per_cvt->channels_max, 8u); |
| 566 | per_cvt->rates |= SUPPORTED_RATES; |
| 567 | per_cvt->formats |= SUPPORTED_FORMATS; |
| 568 | per_cvt->maxbps = max(per_cvt->maxbps, 24u); |
| 569 | } |
| 570 | |
| 571 | spec->chmap.channels_max = max(spec->chmap.channels_max, 8u); |
| 572 | |
| 573 | /* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing |
| 574 | * the link-down as is. Tell the core to allow it. |
| 575 | */ |
| 576 | codec->link_down_at_suspend = 1; |
| 577 | |
| 578 | snd_hda_hdmi_acomp_init(codec, ops: &atihdmi_audio_ops, port2pin: atihdmi_port2pin); |
| 579 | |
| 580 | return 0; |
| 581 | } |
| 582 | |
| 583 | static const struct hda_codec_ops atihdmi_codec_ops = { |
| 584 | .probe = atihdmi_probe, |
| 585 | .remove = snd_hda_hdmi_generic_remove, |
| 586 | .init = atihdmi_init, |
| 587 | .build_pcms = snd_hda_hdmi_generic_build_pcms, |
| 588 | .build_controls = snd_hda_hdmi_generic_build_controls, |
| 589 | .unsol_event = snd_hda_hdmi_generic_unsol_event, |
| 590 | .suspend = snd_hda_hdmi_generic_suspend, |
| 591 | .resume = snd_hda_hdmi_generic_resume, |
| 592 | }; |
| 593 | |
| 594 | /* |
| 595 | * driver entries |
| 596 | */ |
| 597 | static const struct hda_device_id snd_hda_id_atihdmi[] = { |
| 598 | HDA_CODEC_ID(0x1002793c, "RS600 HDMI" ), |
| 599 | HDA_CODEC_ID(0x10027919, "RS600 HDMI" ), |
| 600 | HDA_CODEC_ID(0x1002791a, "RS690/780 HDMI" ), |
| 601 | HDA_CODEC_ID(0x1002aa01, "R6xx HDMI" ), |
| 602 | {} /* terminator */ |
| 603 | }; |
| 604 | MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_atihdmi); |
| 605 | |
| 606 | MODULE_LICENSE("GPL" ); |
| 607 | MODULE_DESCRIPTION("AMD/ATI HDMI HD-audio codec" ); |
| 608 | MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI" ); |
| 609 | |
| 610 | static struct hda_codec_driver atihdmi_driver = { |
| 611 | .id = snd_hda_id_atihdmi, |
| 612 | .ops = &atihdmi_codec_ops, |
| 613 | }; |
| 614 | |
| 615 | module_hda_codec_driver(atihdmi_driver); |
| 616 | |