123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959 |
- /*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: AMD
- *
- */
- #include "reg_helper.h"
- #include "dce_audio.h"
- #include "dce/dce_11_0_d.h"
- #include "dce/dce_11_0_sh_mask.h"
- #define DCE_AUD(audio)\
- container_of(audio, struct dce_audio, base)
- #define CTX \
- aud->base.ctx
- #define DC_LOGGER_INIT()
- #define REG(reg)\
- (aud->regs->reg)
- #undef FN
- #define FN(reg_name, field_name) \
- aud->shifts->field_name, aud->masks->field_name
- #define IX_REG(reg)\
- ix ## reg
- #define AZ_REG_READ(reg_name) \
- read_indirect_azalia_reg(audio, IX_REG(reg_name))
- #define AZ_REG_WRITE(reg_name, value) \
- write_indirect_azalia_reg(audio, IX_REG(reg_name), value)
- static void write_indirect_azalia_reg(struct audio *audio,
- uint32_t reg_index,
- uint32_t reg_data)
- {
- struct dce_audio *aud = DCE_AUD(audio);
- /* AZALIA_F0_CODEC_ENDPOINT_INDEX endpoint index */
- REG_SET(AZALIA_F0_CODEC_ENDPOINT_INDEX, 0,
- AZALIA_ENDPOINT_REG_INDEX, reg_index);
- /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */
- REG_SET(AZALIA_F0_CODEC_ENDPOINT_DATA, 0,
- AZALIA_ENDPOINT_REG_DATA, reg_data);
- DC_LOG_HW_AUDIO("AUDIO:write_indirect_azalia_reg: index: %u data: %u\n",
- reg_index, reg_data);
- }
- static uint32_t read_indirect_azalia_reg(struct audio *audio, uint32_t reg_index)
- {
- struct dce_audio *aud = DCE_AUD(audio);
- uint32_t value = 0;
- /* AZALIA_F0_CODEC_ENDPOINT_INDEX endpoint index */
- REG_SET(AZALIA_F0_CODEC_ENDPOINT_INDEX, 0,
- AZALIA_ENDPOINT_REG_INDEX, reg_index);
- /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */
- value = REG_READ(AZALIA_F0_CODEC_ENDPOINT_DATA);
- DC_LOG_HW_AUDIO("AUDIO:read_indirect_azalia_reg: index: %u data: %u\n",
- reg_index, value);
- return value;
- }
- static bool is_audio_format_supported(
- const struct audio_info *audio_info,
- enum audio_format_code audio_format_code,
- uint32_t *format_index)
- {
- uint32_t index;
- uint32_t max_channe_index = 0;
- bool found = false;
- if (audio_info == NULL)
- return found;
- /* pass through whole array */
- for (index = 0; index < audio_info->mode_count; index++) {
- if (audio_info->modes[index].format_code == audio_format_code) {
- if (found) {
- /* format has multiply entries, choose one with
- * highst number of channels */
- if (audio_info->modes[index].channel_count >
- audio_info->modes[max_channe_index].channel_count) {
- max_channe_index = index;
- }
- } else {
- /* format found, save it's index */
- found = true;
- max_channe_index = index;
- }
- }
- }
- /* return index */
- if (found && format_index != NULL)
- *format_index = max_channe_index;
- return found;
- }
- /*For HDMI, calculate if specified sample rates can fit into a given timing */
- static void check_audio_bandwidth_hdmi(
- const struct audio_crtc_info *crtc_info,
- uint32_t channel_count,
- union audio_sample_rates *sample_rates)
- {
- uint32_t samples;
- uint32_t h_blank;
- bool limit_freq_to_48_khz = false;
- bool limit_freq_to_88_2_khz = false;
- bool limit_freq_to_96_khz = false;
- bool limit_freq_to_174_4_khz = false;
- /* For two channels supported return whatever sink support,unmodified*/
- if (channel_count > 2) {
- /* Based on HDMI spec 1.3 Table 7.5 */
- if ((crtc_info->requested_pixel_clock <= 27000) &&
- (crtc_info->v_active <= 576) &&
- !(crtc_info->interlaced) &&
- !(crtc_info->pixel_repetition == 2 ||
- crtc_info->pixel_repetition == 4)) {
- limit_freq_to_48_khz = true;
- } else if ((crtc_info->requested_pixel_clock <= 27000) &&
- (crtc_info->v_active <= 576) &&
- (crtc_info->interlaced) &&
- (crtc_info->pixel_repetition == 2)) {
- limit_freq_to_88_2_khz = true;
- } else if ((crtc_info->requested_pixel_clock <= 54000) &&
- (crtc_info->v_active <= 576) &&
- !(crtc_info->interlaced)) {
- limit_freq_to_174_4_khz = true;
- }
- }
- /* Also do some calculation for the available Audio Bandwidth for the
- * 8 ch (i.e. for the Layout 1 => ch > 2)
- */
- h_blank = crtc_info->h_total - crtc_info->h_active;
- if (crtc_info->pixel_repetition)
- h_blank *= crtc_info->pixel_repetition;
- /*based on HDMI spec 1.3 Table 7.5 */
- h_blank -= 58;
- /*for Control Period */
- h_blank -= 16;
- samples = h_blank * 10;
- /* Number of Audio Packets (multiplied by 10) per Line (for 8 ch number
- * of Audio samples per line multiplied by 10 - Layout 1)
- */
- samples /= 32;
- samples *= crtc_info->v_active;
- /*Number of samples multiplied by 10, per second */
- samples *= crtc_info->refresh_rate;
- /*Number of Audio samples per second */
- samples /= 10;
- /* @todo do it after deep color is implemented
- * 8xx - deep color bandwidth scaling
- * Extra bandwidth is avaliable in deep color b/c link runs faster than
- * pixel rate. This has the effect of allowing more tmds characters to
- * be transmitted during blank
- */
- switch (crtc_info->color_depth) {
- case COLOR_DEPTH_888:
- samples *= 4;
- break;
- case COLOR_DEPTH_101010:
- samples *= 5;
- break;
- case COLOR_DEPTH_121212:
- samples *= 6;
- break;
- default:
- samples *= 4;
- break;
- }
- samples /= 4;
- /*check limitation*/
- if (samples < 88200)
- limit_freq_to_48_khz = true;
- else if (samples < 96000)
- limit_freq_to_88_2_khz = true;
- else if (samples < 176400)
- limit_freq_to_96_khz = true;
- else if (samples < 192000)
- limit_freq_to_174_4_khz = true;
- if (sample_rates != NULL) {
- /* limit frequencies */
- if (limit_freq_to_174_4_khz)
- sample_rates->rate.RATE_192 = 0;
- if (limit_freq_to_96_khz) {
- sample_rates->rate.RATE_192 = 0;
- sample_rates->rate.RATE_176_4 = 0;
- }
- if (limit_freq_to_88_2_khz) {
- sample_rates->rate.RATE_192 = 0;
- sample_rates->rate.RATE_176_4 = 0;
- sample_rates->rate.RATE_96 = 0;
- }
- if (limit_freq_to_48_khz) {
- sample_rates->rate.RATE_192 = 0;
- sample_rates->rate.RATE_176_4 = 0;
- sample_rates->rate.RATE_96 = 0;
- sample_rates->rate.RATE_88_2 = 0;
- }
- }
- }
- /*For DP SST, calculate if specified sample rates can fit into a given timing */
- static void check_audio_bandwidth_dpsst(
- const struct audio_crtc_info *crtc_info,
- uint32_t channel_count,
- union audio_sample_rates *sample_rates)
- {
- /* do nothing */
- }
- /*For DP MST, calculate if specified sample rates can fit into a given timing */
- static void check_audio_bandwidth_dpmst(
- const struct audio_crtc_info *crtc_info,
- uint32_t channel_count,
- union audio_sample_rates *sample_rates)
- {
- /* do nothing */
- }
- static void check_audio_bandwidth(
- const struct audio_crtc_info *crtc_info,
- uint32_t channel_count,
- enum signal_type signal,
- union audio_sample_rates *sample_rates)
- {
- switch (signal) {
- case SIGNAL_TYPE_HDMI_TYPE_A:
- check_audio_bandwidth_hdmi(
- crtc_info, channel_count, sample_rates);
- break;
- case SIGNAL_TYPE_EDP:
- case SIGNAL_TYPE_DISPLAY_PORT:
- check_audio_bandwidth_dpsst(
- crtc_info, channel_count, sample_rates);
- break;
- case SIGNAL_TYPE_DISPLAY_PORT_MST:
- check_audio_bandwidth_dpmst(
- crtc_info, channel_count, sample_rates);
- break;
- default:
- break;
- }
- }
- /* expose/not expose HBR capability to Audio driver */
- static void set_high_bit_rate_capable(
- struct audio *audio,
- bool capable)
- {
- uint32_t value = 0;
- /* set high bit rate audio capable*/
- value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR);
- set_reg_field_value(value, capable,
- AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR,
- HBR_CAPABLE);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR, value);
- }
- /* set video latency in in ms/2+1 */
- static void set_video_latency(
- struct audio *audio,
- int latency_in_ms)
- {
- uint32_t value = 0;
- if ((latency_in_ms < 0) || (latency_in_ms > 255))
- return;
- value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC);
- set_reg_field_value(value, latency_in_ms,
- AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
- VIDEO_LIPSYNC);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
- value);
- }
- /* set audio latency in in ms/2+1 */
- static void set_audio_latency(
- struct audio *audio,
- int latency_in_ms)
- {
- uint32_t value = 0;
- if (latency_in_ms < 0)
- latency_in_ms = 0;
- if (latency_in_ms > 255)
- latency_in_ms = 255;
- value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC);
- set_reg_field_value(value, latency_in_ms,
- AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
- AUDIO_LIPSYNC);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
- value);
- }
- void dce_aud_az_enable(struct audio *audio)
- {
- uint32_t value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
- DC_LOGGER_INIT();
- set_reg_field_value(value, 1,
- AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
- CLOCK_GATING_DISABLE);
- set_reg_field_value(value, 1,
- AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
- AUDIO_ENABLED);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
- set_reg_field_value(value, 0,
- AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
- CLOCK_GATING_DISABLE);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
- DC_LOG_HW_AUDIO("\n\t========= AUDIO:dce_aud_az_enable: index: %u data: 0x%x\n",
- audio->inst, value);
- }
- void dce_aud_az_disable(struct audio *audio)
- {
- uint32_t value;
- DC_LOGGER_INIT();
- value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
- set_reg_field_value(value, 1,
- AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
- CLOCK_GATING_DISABLE);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
- set_reg_field_value(value, 0,
- AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
- AUDIO_ENABLED);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
- set_reg_field_value(value, 0,
- AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
- CLOCK_GATING_DISABLE);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
- value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
- DC_LOG_HW_AUDIO("\n\t========= AUDIO:dce_aud_az_disable: index: %u data: 0x%x\n",
- audio->inst, value);
- }
- void dce_aud_az_configure(
- struct audio *audio,
- enum signal_type signal,
- const struct audio_crtc_info *crtc_info,
- const struct audio_info *audio_info)
- {
- struct dce_audio *aud = DCE_AUD(audio);
- uint32_t speakers = audio_info->flags.info.ALLSPEAKERS;
- uint32_t value;
- uint32_t field = 0;
- enum audio_format_code audio_format_code;
- uint32_t format_index;
- uint32_t index;
- bool is_ac3_supported = false;
- union audio_sample_rates sample_rate;
- uint32_t strlen = 0;
- value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
- set_reg_field_value(value, 1,
- AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
- CLOCK_GATING_DISABLE);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
- /* Speaker Allocation */
- /*
- uint32_t value;
- uint32_t field = 0;*/
- value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
- set_reg_field_value(value,
- speakers,
- AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
- SPEAKER_ALLOCATION);
- /* LFE_PLAYBACK_LEVEL = LFEPBL
- * LFEPBL = 0 : Unknown or refer to other information
- * LFEPBL = 1 : 0dB playback
- * LFEPBL = 2 : +10dB playback
- * LFE_BL = 3 : Reserved
- */
- set_reg_field_value(value,
- 0,
- AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
- LFE_PLAYBACK_LEVEL);
- /* todo: according to reg spec LFE_PLAYBACK_LEVEL is read only.
- * why are we writing to it? DCE8 does not write this */
- set_reg_field_value(value,
- 0,
- AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
- HDMI_CONNECTION);
- set_reg_field_value(value,
- 0,
- AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
- DP_CONNECTION);
- field = get_reg_field_value(value,
- AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
- EXTRA_CONNECTION_INFO);
- field &= ~0x1;
- set_reg_field_value(value,
- field,
- AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
- EXTRA_CONNECTION_INFO);
- /* set audio for output signal */
- switch (signal) {
- case SIGNAL_TYPE_HDMI_TYPE_A:
- set_reg_field_value(value,
- 1,
- AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
- HDMI_CONNECTION);
- break;
- case SIGNAL_TYPE_EDP:
- case SIGNAL_TYPE_DISPLAY_PORT:
- case SIGNAL_TYPE_DISPLAY_PORT_MST:
- set_reg_field_value(value,
- 1,
- AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
- DP_CONNECTION);
- break;
- default:
- BREAK_TO_DEBUGGER();
- break;
- }
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, value);
- /* Audio Descriptors */
- /* pass through all formats */
- for (format_index = 0; format_index < AUDIO_FORMAT_CODE_COUNT;
- format_index++) {
- audio_format_code =
- (AUDIO_FORMAT_CODE_FIRST + format_index);
- /* those are unsupported, skip programming */
- if (audio_format_code == AUDIO_FORMAT_CODE_1BITAUDIO ||
- audio_format_code == AUDIO_FORMAT_CODE_DST)
- continue;
- value = 0;
- /* check if supported */
- if (is_audio_format_supported(
- audio_info, audio_format_code, &index)) {
- const struct audio_mode *audio_mode =
- &audio_info->modes[index];
- union audio_sample_rates sample_rates =
- audio_mode->sample_rates;
- uint8_t byte2 = audio_mode->max_bit_rate;
- /* adjust specific properties */
- switch (audio_format_code) {
- case AUDIO_FORMAT_CODE_LINEARPCM: {
- check_audio_bandwidth(
- crtc_info,
- audio_mode->channel_count,
- signal,
- &sample_rates);
- byte2 = audio_mode->sample_size;
- set_reg_field_value(value,
- sample_rates.all,
- AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
- SUPPORTED_FREQUENCIES_STEREO);
- }
- break;
- case AUDIO_FORMAT_CODE_AC3:
- is_ac3_supported = true;
- break;
- case AUDIO_FORMAT_CODE_DOLBYDIGITALPLUS:
- case AUDIO_FORMAT_CODE_DTS_HD:
- case AUDIO_FORMAT_CODE_MAT_MLP:
- case AUDIO_FORMAT_CODE_DST:
- case AUDIO_FORMAT_CODE_WMAPRO:
- byte2 = audio_mode->vendor_specific;
- break;
- default:
- break;
- }
- /* fill audio format data */
- set_reg_field_value(value,
- audio_mode->channel_count - 1,
- AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
- MAX_CHANNELS);
- set_reg_field_value(value,
- sample_rates.all,
- AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
- SUPPORTED_FREQUENCIES);
- set_reg_field_value(value,
- byte2,
- AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
- DESCRIPTOR_BYTE_2);
- } /* if */
- AZ_REG_WRITE(
- AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0 + format_index,
- value);
- } /* for */
- if (is_ac3_supported)
- /* todo: this reg global. why program global register? */
- REG_WRITE(AZALIA_F0_CODEC_FUNCTION_PARAMETER_STREAM_FORMATS,
- 0x05);
- /* check for 192khz/8-Ch support for HBR requirements */
- sample_rate.all = 0;
- sample_rate.rate.RATE_192 = 1;
- check_audio_bandwidth(
- crtc_info,
- 8,
- signal,
- &sample_rate);
- set_high_bit_rate_capable(audio, sample_rate.rate.RATE_192);
- /* Audio and Video Lipsync */
- set_video_latency(audio, audio_info->video_latency);
- set_audio_latency(audio, audio_info->audio_latency);
- value = 0;
- set_reg_field_value(value, audio_info->manufacture_id,
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
- MANUFACTURER_ID);
- set_reg_field_value(value, audio_info->product_id,
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
- PRODUCT_ID);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
- value);
- value = 0;
- /*get display name string length */
- while (audio_info->display_name[strlen++] != '\0') {
- if (strlen >=
- MAX_HW_AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS)
- break;
- }
- set_reg_field_value(value, strlen,
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1,
- SINK_DESCRIPTION_LEN);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1,
- value);
- /*
- *write the port ID:
- *PORT_ID0 = display index
- *PORT_ID1 = 16bit BDF
- *(format MSB->LSB: 8bit Bus, 5bit Device, 3bit Function)
- */
- value = 0;
- set_reg_field_value(value, audio_info->port_id[0],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2,
- PORT_ID0);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2, value);
- value = 0;
- set_reg_field_value(value, audio_info->port_id[1],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3,
- PORT_ID1);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3, value);
- /*write the 18 char monitor string */
- value = 0;
- set_reg_field_value(value, audio_info->display_name[0],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
- DESCRIPTION0);
- set_reg_field_value(value, audio_info->display_name[1],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
- DESCRIPTION1);
- set_reg_field_value(value, audio_info->display_name[2],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
- DESCRIPTION2);
- set_reg_field_value(value, audio_info->display_name[3],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
- DESCRIPTION3);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4, value);
- value = 0;
- set_reg_field_value(value, audio_info->display_name[4],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
- DESCRIPTION4);
- set_reg_field_value(value, audio_info->display_name[5],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
- DESCRIPTION5);
- set_reg_field_value(value, audio_info->display_name[6],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
- DESCRIPTION6);
- set_reg_field_value(value, audio_info->display_name[7],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
- DESCRIPTION7);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5, value);
- value = 0;
- set_reg_field_value(value, audio_info->display_name[8],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
- DESCRIPTION8);
- set_reg_field_value(value, audio_info->display_name[9],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
- DESCRIPTION9);
- set_reg_field_value(value, audio_info->display_name[10],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
- DESCRIPTION10);
- set_reg_field_value(value, audio_info->display_name[11],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
- DESCRIPTION11);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6, value);
- value = 0;
- set_reg_field_value(value, audio_info->display_name[12],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
- DESCRIPTION12);
- set_reg_field_value(value, audio_info->display_name[13],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
- DESCRIPTION13);
- set_reg_field_value(value, audio_info->display_name[14],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
- DESCRIPTION14);
- set_reg_field_value(value, audio_info->display_name[15],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
- DESCRIPTION15);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7, value);
- value = 0;
- set_reg_field_value(value, audio_info->display_name[16],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
- DESCRIPTION16);
- set_reg_field_value(value, audio_info->display_name[17],
- AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
- DESCRIPTION17);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8, value);
- value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
- set_reg_field_value(value, 0,
- AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
- CLOCK_GATING_DISABLE);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
- }
- /*
- * todo: wall clk related functionality probably belong to clock_src.
- */
- /* search pixel clock value for Azalia HDMI Audio */
- static void get_azalia_clock_info_hdmi(
- uint32_t crtc_pixel_clock_in_khz,
- uint32_t actual_pixel_clock_in_khz,
- struct azalia_clock_info *azalia_clock_info)
- {
- /* audio_dto_phase= 24 * 10,000;
- * 24MHz in [100Hz] units */
- azalia_clock_info->audio_dto_phase =
- 24 * 10000;
- /* audio_dto_module = PCLKFrequency * 10,000;
- * [khz] -> [100Hz] */
- azalia_clock_info->audio_dto_module =
- actual_pixel_clock_in_khz * 10;
- }
- static void get_azalia_clock_info_dp(
- uint32_t requested_pixel_clock_in_khz,
- const struct audio_pll_info *pll_info,
- struct azalia_clock_info *azalia_clock_info)
- {
- /* Reported dpDtoSourceClockInkhz value for
- * DCE8 already adjusted for SS, do not need any
- * adjustment here anymore
- */
- /*audio_dto_phase = 24 * 10,000;
- * 24MHz in [100Hz] units */
- azalia_clock_info->audio_dto_phase = 24 * 10000;
- /*audio_dto_module = dpDtoSourceClockInkhz * 10,000;
- * [khz] ->[100Hz] */
- azalia_clock_info->audio_dto_module =
- pll_info->dp_dto_source_clock_in_khz * 10;
- }
- void dce_aud_wall_dto_setup(
- struct audio *audio,
- enum signal_type signal,
- const struct audio_crtc_info *crtc_info,
- const struct audio_pll_info *pll_info)
- {
- struct dce_audio *aud = DCE_AUD(audio);
- struct azalia_clock_info clock_info = { 0 };
- if (dc_is_hdmi_signal(signal)) {
- uint32_t src_sel;
- /*DTO0 Programming goal:
- -generate 24MHz, 128*Fs from 24MHz
- -use DTO0 when an active HDMI port is connected
- (optionally a DP is connected) */
- /* calculate DTO settings */
- get_azalia_clock_info_hdmi(
- crtc_info->requested_pixel_clock,
- crtc_info->calculated_pixel_clock,
- &clock_info);
- DC_LOG_HW_AUDIO("\n%s:Input::requested_pixel_clock = %d"\
- "calculated_pixel_clock =%d\n"\
- "audio_dto_module = %d audio_dto_phase =%d \n\n", __func__,\
- crtc_info->requested_pixel_clock,\
- crtc_info->calculated_pixel_clock,\
- clock_info.audio_dto_module,\
- clock_info.audio_dto_phase);
- /* On TN/SI, Program DTO source select and DTO select before
- programming DTO modulo and DTO phase. These bits must be
- programmed first, otherwise there will be no HDMI audio at boot
- up. This is a HW sequence change (different from old ASICs).
- Caution when changing this programming sequence.
- HDMI enabled, using DTO0
- program master CRTC for DTO0 */
- src_sel = pll_info->dto_source - DTO_SOURCE_ID0;
- REG_UPDATE_2(DCCG_AUDIO_DTO_SOURCE,
- DCCG_AUDIO_DTO0_SOURCE_SEL, src_sel,
- DCCG_AUDIO_DTO_SEL, 0);
- /* module */
- REG_UPDATE(DCCG_AUDIO_DTO0_MODULE,
- DCCG_AUDIO_DTO0_MODULE, clock_info.audio_dto_module);
- /* phase */
- REG_UPDATE(DCCG_AUDIO_DTO0_PHASE,
- DCCG_AUDIO_DTO0_PHASE, clock_info.audio_dto_phase);
- } else {
- /*DTO1 Programming goal:
- -generate 24MHz, 512*Fs, 128*Fs from 24MHz
- -default is to used DTO1, and switch to DTO0 when an audio
- master HDMI port is connected
- -use as default for DP
- calculate DTO settings */
- get_azalia_clock_info_dp(
- crtc_info->requested_pixel_clock,
- pll_info,
- &clock_info);
- /* Program DTO select before programming DTO modulo and DTO
- phase. default to use DTO1 */
- REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
- DCCG_AUDIO_DTO_SEL, 1);
- REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
- DCCG_AUDIO_DTO_SEL, 1);
- /* DCCG_AUDIO_DTO2_USE_512FBR_DTO, 1)
- * Select 512fs for DP TODO: web register definition
- * does not match register header file
- * DCE11 version it's commented out while DCE8 it's set to 1
- */
- /* module */
- REG_UPDATE(DCCG_AUDIO_DTO1_MODULE,
- DCCG_AUDIO_DTO1_MODULE, clock_info.audio_dto_module);
- /* phase */
- REG_UPDATE(DCCG_AUDIO_DTO1_PHASE,
- DCCG_AUDIO_DTO1_PHASE, clock_info.audio_dto_phase);
- REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
- DCCG_AUDIO_DTO2_USE_512FBR_DTO, 1);
- }
- }
- static bool dce_aud_endpoint_valid(struct audio *audio)
- {
- uint32_t value;
- uint32_t port_connectivity;
- value = AZ_REG_READ(
- AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
- port_connectivity = get_reg_field_value(value,
- AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT,
- PORT_CONNECTIVITY);
- return !(port_connectivity == 1);
- }
- /* initialize HW state */
- void dce_aud_hw_init(
- struct audio *audio)
- {
- uint32_t value;
- struct dce_audio *aud = DCE_AUD(audio);
- /* we only need to program the following registers once, so we only do
- it for the inst 0*/
- if (audio->inst != 0)
- return;
- /* Suport R5 - 32khz
- * Suport R6 - 44.1khz
- * Suport R7 - 48khz
- */
- /*disable clock gating before write to endpoint register*/
- value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
- set_reg_field_value(value, 1,
- AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
- CLOCK_GATING_DISABLE);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
- REG_UPDATE(AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES,
- AUDIO_RATE_CAPABILITIES, 0x70);
- /*Keep alive bit to verify HW block in BU. */
- REG_UPDATE_2(AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES,
- CLKSTOP, 1,
- EPSS, 1);
- set_reg_field_value(value, 0,
- AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
- CLOCK_GATING_DISABLE);
- AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
- }
- static const struct audio_funcs funcs = {
- .endpoint_valid = dce_aud_endpoint_valid,
- .hw_init = dce_aud_hw_init,
- .wall_dto_setup = dce_aud_wall_dto_setup,
- .az_enable = dce_aud_az_enable,
- .az_disable = dce_aud_az_disable,
- .az_configure = dce_aud_az_configure,
- .destroy = dce_aud_destroy,
- };
- void dce_aud_destroy(struct audio **audio)
- {
- struct dce_audio *aud = DCE_AUD(*audio);
- kfree(aud);
- *audio = NULL;
- }
- struct audio *dce_audio_create(
- struct dc_context *ctx,
- unsigned int inst,
- const struct dce_audio_registers *reg,
- const struct dce_audio_shift *shifts,
- const struct dce_aduio_mask *masks
- )
- {
- struct dce_audio *audio = kzalloc(sizeof(*audio), GFP_KERNEL);
- if (audio == NULL) {
- ASSERT_CRITICAL(audio);
- return NULL;
- }
- audio->base.ctx = ctx;
- audio->base.inst = inst;
- audio->base.funcs = &funcs;
- audio->regs = reg;
- audio->shifts = shifts;
- audio->masks = masks;
- return &audio->base;
- }
|