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;
}
}
+ cfg_val.cfg_regx.val_bit = 1;
had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
return 0;
}
}
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);
/*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++)
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);
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);
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
*
*
* 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;
*
* 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));
}
{
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;
{
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;
}
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);
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);
{
int retval = 0;
u32 disp_samp_freq, n_param;
+ u32 link_rate = 0;
struct snd_intelhad *intelhaddata;
intelhaddata = snd_pcm_substream_chip(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);
struct snd_intel_had_interface *had_interface;
void *had_pvt_data;
int tmds_clock_speed;
+ bool dp_output;
+ int link_rate;
unsigned int had_config_offset;
int hdmi_audio_interrupt_mask;
struct work_struct hdmi_audio_wq;
dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val);
+ if (ctx->dp_output) {
+ if ((reg == AUDIO_HDMI_CONFIG_A) ||
+ (reg == AUDIO_HDMI_CONFIG_B) ||
+ (reg == AUDIO_HDMI_CONFIG_C)) {
+ if (val & AUD_CONFIG_VALID_BIT)
+ val = val | AUD_CONFIG_DP_MODE |
+ AUD_CONFIG_BLOCK_BIT;
+ }
+ }
iowrite32(val, (ctx->mmio_start+reg));
return 0;
val_tmp = (val & mask) |
((ioread32(ctx->mmio_start + reg)) & ~mask);
+ if (ctx->dp_output) {
+ if ((reg == AUDIO_HDMI_CONFIG_A) ||
+ (reg == AUDIO_HDMI_CONFIG_B) ||
+ (reg == AUDIO_HDMI_CONFIG_C)) {
+ if (val_tmp & AUD_CONFIG_VALID_BIT)
+ val_tmp = val_tmp | AUD_CONFIG_DP_MODE |
+ AUD_CONFIG_BLOCK_BIT;
+ }
+ }
+
iowrite32(val_tmp, (ctx->mmio_start+reg));
dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__,
reg, val_tmp);
/* ToDo: Verify if sampling freq logic is correct */
*(u32 *)capabilities = ctx->tmds_clock_speed;
dev_dbg(&hlpe_pdev->dev, "%s: tmds_clock_speed = 0x%x\n",
- __func__, ctx->tmds_clock_speed);
+ __func__, ctx->tmds_clock_speed);
+ break;
+ case HAD_GET_LINK_RATE:
+ /* ToDo: Verify if sampling freq logic is correct */
+ *(u32 *)capabilities = ctx->link_rate;
+ dev_dbg(&hlpe_pdev->dev, "%s: link rate = 0x%x\n",
+ __func__, ctx->link_rate);
+ break;
+ case HAD_GET_DP_OUTPUT:
+ *(u32 *)capabilities = ctx->dp_output;
+ dev_dbg(&hlpe_pdev->dev, "%s: dp_output = %d\n",
+ __func__, ctx->dp_output);
break;
default:
break;
if (pdata->tmds_clock_speed) {
ctx->tmds_clock_speed = pdata->tmds_clock_speed;
+ ctx->dp_output = pdata->dp_output;
+ ctx->link_rate = pdata->link_rate;
mid_hdmi_audio_signal_event(HAD_EVENT_MODE_CHANGING);
}
} else