#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);
REG_SET(AZALIA_F0_CODEC_ENDPOINT_INDEX, 0,
AZALIA_ENDPOINT_REG_INDEX, reg_index);
REG_SET(AZALIA_F0_CODEC_ENDPOINT_DATA, 0,
AZALIA_ENDPOINT_REG_DATA, 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;
REG_SET(AZALIA_F0_CODEC_ENDPOINT_INDEX, 0,
AZALIA_ENDPOINT_REG_INDEX, reg_index);
value = REG_READ(AZALIA_F0_CODEC_ENDPOINT_DATA);
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;
for (index = 0; index < audio_info->mode_count; index++) {
if (audio_info->modes[index].format_code == audio_format_code) {
if (found) {
if (audio_info->modes[index].channel_count >
audio_info->modes[max_channe_index].channel_count) {
max_channe_index = index;
}
} else {
found = true;
max_channe_index = index;
}
}
}
if (found && format_index != NULL)
*format_index = max_channe_index;
return found;
}
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;
if (!crtc_info)
return;
if (channel_count > 2) {
if ((crtc_info->requested_pixel_clock_100Hz <= 270000) &&
(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_100Hz <= 270000) &&
(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_100Hz <= 540000) &&
(crtc_info->v_active <= 576) &&
!(crtc_info->interlaced)) {
limit_freq_to_174_4_khz = true;
}
}
h_blank = crtc_info->h_total - crtc_info->h_active;
if (crtc_info->pixel_repetition)
h_blank *= crtc_info->pixel_repetition;
h_blank -= 58;
h_blank -= 16;
samples = h_blank * 10;
samples /= 32;
samples *= crtc_info->v_active;
samples *= crtc_info->refresh_rate;
samples /= 10;
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;
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) {
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;
}
}
}
static void check_audio_bandwidth_dpsst(
const struct audio_crtc_info *crtc_info,
uint32_t channel_count,
union audio_sample_rates *sample_rates)
{
}
static void check_audio_bandwidth_dpmst(
const struct audio_crtc_info *crtc_info,
uint32_t channel_count,
union audio_sample_rates *sample_rates)
{
}
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;
}
}
static void set_high_bit_rate_capable(
struct audio *audio,
bool capable)
{
uint32_t value = 0;
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);
}
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);
}
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);
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);
set_reg_field_value(value,
0,
AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
LFE_PLAYBACK_LEVEL);
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);
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);
value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_ACP_DATA);
set_reg_field_value(
value,
audio_info->flags.info.SUPPORT_AI,
AZALIA_F0_CODEC_PIN_CONTROL_ACP_DATA,
SUPPORTS_AI);
AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_ACP_DATA, value);
for (format_index = 0; format_index < AUDIO_FORMAT_CODE_COUNT;
format_index++) {
audio_format_code =
(AUDIO_FORMAT_CODE_FIRST + format_index);
if (audio_format_code == AUDIO_FORMAT_CODE_1BITAUDIO ||
audio_format_code == AUDIO_FORMAT_CODE_DST)
continue;
value = 0;
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;
uint8_t channel_count = audio_mode->channel_count;
switch (audio_format_code) {
case AUDIO_FORMAT_CODE_LINEARPCM: {
check_audio_bandwidth(
crtc_info,
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;
}
set_reg_field_value(value,
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);
}
AZ_REG_WRITE(
AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0 + format_index,
value);
}
if (is_ac3_supported)
REG_WRITE(AZALIA_F0_CODEC_FUNCTION_PARAMETER_STREAM_FORMATS,
0x05);
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);
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;
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);
DC_LOG_HW_AUDIO("\n\tAUDIO:az_configure: index: %u data, 0x%x, displayName %s: \n",
audio->inst, value, audio_info->display_name);
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);
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);
}
static void get_azalia_clock_info_hdmi(
uint32_t crtc_pixel_clock_100hz,
uint32_t actual_pixel_clock_100Hz,
struct azalia_clock_info *azalia_clock_info)
{
azalia_clock_info->audio_dto_phase =
24 * 10000;
azalia_clock_info->audio_dto_module =
actual_pixel_clock_100Hz;
}
static void get_azalia_clock_info_dp(
uint32_t requested_pixel_clock_100Hz,
const struct audio_pll_info *pll_info,
struct azalia_clock_info *azalia_clock_info)
{
azalia_clock_info->audio_dto_phase = 24 * 10000;
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_tmds_signal(signal)) {
uint32_t src_sel;
get_azalia_clock_info_hdmi(
crtc_info->requested_pixel_clock_100Hz,
crtc_info->calculated_pixel_clock_100Hz,
&clock_info);
DC_LOG_HW_AUDIO("\n%s:Input::requested_pixel_clock_100Hz = %d"\
"calculated_pixel_clock_100Hz =%d\n"\
"audio_dto_module = %d audio_dto_phase =%d \n\n", __func__,\
crtc_info->requested_pixel_clock_100Hz,\
crtc_info->calculated_pixel_clock_100Hz,\
clock_info.audio_dto_module,\
clock_info.audio_dto_phase);
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);
REG_UPDATE(DCCG_AUDIO_DTO0_MODULE,
DCCG_AUDIO_DTO0_MODULE, clock_info.audio_dto_module);
REG_UPDATE(DCCG_AUDIO_DTO0_PHASE,
DCCG_AUDIO_DTO0_PHASE, clock_info.audio_dto_phase);
} else {
get_azalia_clock_info_dp(
crtc_info->requested_pixel_clock_100Hz,
pll_info,
&clock_info);
REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
DCCG_AUDIO_DTO_SEL, 1);
REG_UPDATE(DCCG_AUDIO_DTO1_MODULE,
DCCG_AUDIO_DTO1_MODULE, clock_info.audio_dto_module);
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);
}
}
#if defined(CONFIG_DRM_AMD_DC_SI)
static void dce60_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;
get_azalia_clock_info_hdmi(
crtc_info->requested_pixel_clock_100Hz,
crtc_info->calculated_pixel_clock_100Hz,
&clock_info);
DC_LOG_HW_AUDIO("\n%s:Input::requested_pixel_clock_100Hz = %d"\
"calculated_pixel_clock_100Hz =%d\n"\
"audio_dto_module = %d audio_dto_phase =%d \n\n", __func__,\
crtc_info->requested_pixel_clock_100Hz,\
crtc_info->calculated_pixel_clock_100Hz,\
clock_info.audio_dto_module,\
clock_info.audio_dto_phase);
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);
REG_UPDATE(DCCG_AUDIO_DTO0_MODULE,
DCCG_AUDIO_DTO0_MODULE, clock_info.audio_dto_module);
REG_UPDATE(DCCG_AUDIO_DTO0_PHASE,
DCCG_AUDIO_DTO0_PHASE, clock_info.audio_dto_phase);
} else {
get_azalia_clock_info_dp(
crtc_info->requested_pixel_clock_100Hz,
pll_info,
&clock_info);
REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
DCCG_AUDIO_DTO_SEL, 1);
REG_UPDATE(DCCG_AUDIO_DTO1_MODULE,
DCCG_AUDIO_DTO1_MODULE, clock_info.audio_dto_module);
REG_UPDATE(DCCG_AUDIO_DTO1_PHASE,
DCCG_AUDIO_DTO1_PHASE, clock_info.audio_dto_phase);
}
}
#endif
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);
}
void dce_aud_hw_init(
struct audio *audio)
{
uint32_t value;
struct dce_audio *aud = DCE_AUD(audio);
if (audio->inst != 0)
return;
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);
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,
};
#if defined(CONFIG_DRM_AMD_DC_SI)
static const struct audio_funcs dce60_funcs = {
.endpoint_valid = dce_aud_endpoint_valid,
.hw_init = dce_aud_hw_init,
.wall_dto_setup = dce60_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,
};
#endif
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_audio_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;
}
#if defined(CONFIG_DRM_AMD_DC_SI)
struct audio *dce60_audio_create(
struct dc_context *ctx,
unsigned int inst,
const struct dce_audio_registers *reg,
const struct dce_audio_shift *shifts,
const struct dce_audio_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 = &dce60_funcs;
audio->regs = reg;
audio->shifts = shifts;
audio->masks = masks;
return &audio->base;
}
#endif