|
@@ -396,6 +396,7 @@ static int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream,
|
|
|
else
|
|
|
cfg_val.cfg_regx_v2.layout = LAYOUT1;
|
|
|
|
|
|
+ cfg_val.cfg_regx_v2.val_bit = 1;
|
|
|
had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
|
|
|
return 0;
|
|
|
}
|
|
@@ -447,6 +448,7 @@ static int snd_intelhad_prog_audio_ctrl_v1(struct snd_pcm_substream *substream,
|
|
|
|
|
|
}
|
|
|
|
|
|
+ cfg_val.cfg_regx.val_bit = 1;
|
|
|
had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
|
|
|
return 0;
|
|
|
}
|
|
@@ -548,6 +550,7 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
|
|
|
}
|
|
|
|
|
|
had_get_caps(HAD_GET_ELD, &intelhaddata->eeld);
|
|
|
+ had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output);
|
|
|
|
|
|
pr_debug("eeld.speaker_allocation_block = %x\n",
|
|
|
intelhaddata->eeld.speaker_allocation_block);
|
|
@@ -685,7 +688,7 @@ static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream,
|
|
|
|
|
|
/*Calculte the byte wide checksum for all valid DIP words*/
|
|
|
for (i = 0; i < BYTES_PER_WORD; i++)
|
|
|
- checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
|
|
+ checksum += (HDMI_INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
|
|
for (i = 0; i < BYTES_PER_WORD; i++)
|
|
|
checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
|
|
for (i = 0; i < BYTES_PER_WORD; i++)
|
|
@@ -693,7 +696,7 @@ static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream,
|
|
|
|
|
|
frame2.fr2_regx.chksum = -(checksum);
|
|
|
|
|
|
- had_write_register(AUD_HDMIW_INFOFR, INFO_FRAME_WORD1);
|
|
|
+ had_write_register(AUD_HDMIW_INFOFR, HDMI_INFO_FRAME_WORD1);
|
|
|
had_write_register(AUD_HDMIW_INFOFR, frame2.fr2_val);
|
|
|
had_write_register(AUD_HDMIW_INFOFR, frame3.fr3_val);
|
|
|
|
|
@@ -722,28 +725,35 @@ static void snd_intelhad_prog_dip_v2(struct snd_pcm_substream *substream,
|
|
|
union aud_info_frame2 frame2 = {.fr2_val = 0};
|
|
|
union aud_info_frame3 frame3 = {.fr3_val = 0};
|
|
|
u8 checksum = 0;
|
|
|
+ u32 info_frame;
|
|
|
int channels;
|
|
|
|
|
|
channels = substream->runtime->channels;
|
|
|
|
|
|
had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
|
|
|
|
|
|
- frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1;
|
|
|
+ if (intelhaddata->dp_output) {
|
|
|
+ info_frame = DP_INFO_FRAME_WORD1;
|
|
|
+ frame2.fr2_val = 1;
|
|
|
+ } else {
|
|
|
+ info_frame = HDMI_INFO_FRAME_WORD1;
|
|
|
+ frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1;
|
|
|
|
|
|
- frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation(
|
|
|
- intelhaddata, channels);
|
|
|
+ frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation(
|
|
|
+ intelhaddata, channels);
|
|
|
|
|
|
- /*Calculte the byte wide checksum for all valid DIP words*/
|
|
|
- for (i = 0; i < BYTES_PER_WORD; i++)
|
|
|
- checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
|
|
- for (i = 0; i < BYTES_PER_WORD; i++)
|
|
|
- checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
|
|
- for (i = 0; i < BYTES_PER_WORD; i++)
|
|
|
- checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
|
|
+ /*Calculte the byte wide checksum for all valid DIP words*/
|
|
|
+ for (i = 0; i < BYTES_PER_WORD; i++)
|
|
|
+ checksum += (info_frame >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
|
|
+ for (i = 0; i < BYTES_PER_WORD; i++)
|
|
|
+ checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
|
|
+ for (i = 0; i < BYTES_PER_WORD; i++)
|
|
|
+ checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
|
|
|
|
|
|
- frame2.fr2_regx.chksum = -(checksum);
|
|
|
+ frame2.fr2_regx.chksum = -(checksum);
|
|
|
+ }
|
|
|
|
|
|
- had_write_register(AUD_HDMIW_INFOFR_v2, INFO_FRAME_WORD1);
|
|
|
+ had_write_register(AUD_HDMIW_INFOFR_v2, info_frame);
|
|
|
had_write_register(AUD_HDMIW_INFOFR_v2, frame2.fr2_val);
|
|
|
had_write_register(AUD_HDMIW_INFOFR_v2, frame3.fr3_val);
|
|
|
|
|
@@ -839,6 +849,85 @@ int snd_intelhad_read_len(struct snd_intelhad *intelhaddata)
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
+static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate)
|
|
|
+{
|
|
|
+ u32 maud_val;
|
|
|
+
|
|
|
+ /* Select maud according to DP 1.2 spec*/
|
|
|
+ if (link_rate == DP_2_7_GHZ) {
|
|
|
+ switch (aud_samp_freq) {
|
|
|
+ case AUD_SAMPLE_RATE_32:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AUD_SAMPLE_RATE_44_1:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AUD_SAMPLE_RATE_48:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AUD_SAMPLE_RATE_88_2:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AUD_SAMPLE_RATE_96:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AUD_SAMPLE_RATE_176_4:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HAD_MAX_RATE:
|
|
|
+ maud_val = HAD_MAX_RATE_DP_2_7_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ maud_val = -EINVAL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else if (link_rate == DP_1_62_GHZ) {
|
|
|
+ switch (aud_samp_freq) {
|
|
|
+ case AUD_SAMPLE_RATE_32:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AUD_SAMPLE_RATE_44_1:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AUD_SAMPLE_RATE_48:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AUD_SAMPLE_RATE_88_2:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AUD_SAMPLE_RATE_96:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AUD_SAMPLE_RATE_176_4:
|
|
|
+ maud_val = AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HAD_MAX_RATE:
|
|
|
+ maud_val = HAD_MAX_RATE_DP_1_62_MAUD_VAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ maud_val = -EINVAL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else
|
|
|
+ maud_val = -EINVAL;
|
|
|
+
|
|
|
+ return maud_val;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* snd_intelhad_prog_cts_v1 - Program HDMI audio CTS value
|
|
|
*
|
|
@@ -849,8 +938,9 @@ int snd_intelhad_read_len(struct snd_intelhad *intelhaddata)
|
|
|
*
|
|
|
* Program CTS register based on the audio and display sampling frequency
|
|
|
*/
|
|
|
-static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, u32 n_param,
|
|
|
- struct snd_intelhad *intelhaddata)
|
|
|
+static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds,
|
|
|
+ u32 link_rate, u32 n_param,
|
|
|
+ struct snd_intelhad *intelhaddata)
|
|
|
{
|
|
|
u32 cts_val;
|
|
|
u64 dividend, divisor;
|
|
@@ -874,18 +964,24 @@ static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, u32 n_param,
|
|
|
*
|
|
|
* Program CTS register based on the audio and display sampling frequency
|
|
|
*/
|
|
|
-static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds, u32 n_param,
|
|
|
- struct snd_intelhad *intelhaddata)
|
|
|
+static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds,
|
|
|
+ u32 link_rate, u32 n_param,
|
|
|
+ struct snd_intelhad *intelhaddata)
|
|
|
{
|
|
|
u32 cts_val;
|
|
|
u64 dividend, divisor;
|
|
|
|
|
|
- /* Calculate CTS according to HDMI 1.3a spec*/
|
|
|
- dividend = (u64)tmds * n_param*1000;
|
|
|
- divisor = 128 * aud_samp_freq;
|
|
|
- cts_val = div64_u64(dividend, divisor);
|
|
|
+ if (intelhaddata->dp_output) {
|
|
|
+ /* Substitute cts_val with Maud according to DP 1.2 spec*/
|
|
|
+ cts_val = had_calculate_maud_value(aud_samp_freq, link_rate);
|
|
|
+ } else {
|
|
|
+ /* Calculate CTS according to HDMI 1.3a spec*/
|
|
|
+ dividend = (u64)tmds * n_param*1000;
|
|
|
+ divisor = 128 * aud_samp_freq;
|
|
|
+ cts_val = div64_u64(dividend, divisor);
|
|
|
+ }
|
|
|
pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n",
|
|
|
- tmds, n_param, cts_val);
|
|
|
+ tmds, n_param, cts_val);
|
|
|
had_write_register(AUD_HDMI_CTS, (BIT(24) | cts_val));
|
|
|
}
|
|
|
|
|
@@ -970,7 +1066,18 @@ static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param,
|
|
|
{
|
|
|
s32 n_val;
|
|
|
|
|
|
- n_val = had_calculate_n_value(aud_samp_freq);
|
|
|
+ if (intelhaddata->dp_output) {
|
|
|
+ /*
|
|
|
+ * According to DP specs, Maud and Naud values hold
|
|
|
+ * a relationship, which is stated as:
|
|
|
+ * Maud/Naud = 512 * fs / f_LS_Clk
|
|
|
+ * where, fs is the sampling frequency of the audio stream
|
|
|
+ * and Naud is 32768 for Async clock.
|
|
|
+ */
|
|
|
+
|
|
|
+ n_val = DP_NAUD_VAL;
|
|
|
+ } else
|
|
|
+ n_val = had_calculate_n_value(aud_samp_freq);
|
|
|
|
|
|
if (n_val < 0)
|
|
|
return n_val;
|
|
@@ -1343,6 +1450,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
|
|
|
{
|
|
|
int retval;
|
|
|
u32 disp_samp_freq, n_param;
|
|
|
+ u32 link_rate = 0;
|
|
|
struct snd_intelhad *intelhaddata;
|
|
|
struct snd_pcm_runtime *runtime;
|
|
|
struct had_pvt_data *had_stream;
|
|
@@ -1387,6 +1495,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
|
|
|
}
|
|
|
|
|
|
had_get_caps(HAD_GET_ELD, &intelhaddata->eeld);
|
|
|
+ had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output);
|
|
|
|
|
|
retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param,
|
|
|
intelhaddata);
|
|
@@ -1394,8 +1503,14 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
|
|
|
pr_err("programming N value failed %#x\n", retval);
|
|
|
goto prep_end;
|
|
|
}
|
|
|
+
|
|
|
+ if (intelhaddata->dp_output)
|
|
|
+ had_get_caps(HAD_GET_LINK_RATE, &link_rate);
|
|
|
+
|
|
|
+
|
|
|
intelhaddata->ops->prog_cts(substream->runtime->rate,
|
|
|
- disp_samp_freq, n_param, intelhaddata);
|
|
|
+ disp_samp_freq, link_rate,
|
|
|
+ n_param, intelhaddata);
|
|
|
|
|
|
intelhaddata->ops->prog_dip(substream, intelhaddata);
|
|
|
|
|
@@ -1503,6 +1618,7 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream)
|
|
|
{
|
|
|
int retval = 0;
|
|
|
u32 disp_samp_freq, n_param;
|
|
|
+ u32 link_rate = 0;
|
|
|
struct snd_intelhad *intelhaddata;
|
|
|
|
|
|
intelhaddata = snd_pcm_substream_chip(substream);
|
|
@@ -1523,8 +1639,13 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream)
|
|
|
pr_err("programming N value failed %#x\n", retval);
|
|
|
goto out;
|
|
|
}
|
|
|
+
|
|
|
+ if (intelhaddata->dp_output)
|
|
|
+ had_get_caps(HAD_GET_LINK_RATE, &link_rate);
|
|
|
+
|
|
|
intelhaddata->ops->prog_cts(substream->runtime->rate,
|
|
|
- disp_samp_freq, n_param, intelhaddata);
|
|
|
+ disp_samp_freq, link_rate,
|
|
|
+ n_param, intelhaddata);
|
|
|
|
|
|
/* Enable Audio */
|
|
|
intelhaddata->ops->enable_audio(substream, 1);
|