Jelajahi Sumber

Merge branch 'topic/intel-lpe-audio-dp' into for-next

Merged more patches for Intel LPE audio driver, now to support DP audio.
Takashi Iwai 9 tahun lalu
induk
melakukan
374a504025

+ 2 - 1
drivers/gpu/drm/i915/i915_drv.h

@@ -3401,7 +3401,8 @@ int  intel_lpe_audio_init(struct drm_i915_private *dev_priv);
 void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv);
 void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv);
 void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
-			void *eld, int port, int tmds_clk_speed);
+			    void *eld, int port, int pipe, int tmds_clk_speed,
+			    bool dp_output, int link_rate);
 
 /* intel_i2c.c */
 extern int intel_setup_gmbus(struct drm_device *dev);

+ 10 - 0
drivers/gpu/drm/i915/i915_reg.h

@@ -2061,6 +2061,16 @@ enum skl_disp_power_wells {
 #define I915_HDMI_LPE_AUDIO_BASE	(VLV_DISPLAY_BASE + 0x65000)
 #define I915_HDMI_LPE_AUDIO_SIZE	0x1000
 
+/* DisplayPort Audio w/ LPE */
+#define _VLV_AUD_PORT_EN_B_DBG		(VLV_DISPLAY_BASE + 0x62F20)
+#define _VLV_AUD_PORT_EN_C_DBG		(VLV_DISPLAY_BASE + 0x62F30)
+#define _VLV_AUD_PORT_EN_D_DBG		(VLV_DISPLAY_BASE + 0x62F34)
+#define VLV_AUD_PORT_EN_DBG(port)	_MMIO_PORT3((port) - PORT_B,	   \
+						    _VLV_AUD_PORT_EN_B_DBG, \
+						    _VLV_AUD_PORT_EN_C_DBG, \
+						    _VLV_AUD_PORT_EN_D_DBG)
+#define VLV_AMP_MUTE		        (1 << 1)
+
 #define GEN6_BSD_RNCID			_MMIO(0x12198)
 
 #define GEN7_FF_THREAD_MODE		_MMIO(0x20a0)

+ 25 - 13
drivers/gpu/drm/i915/intel_audio.c

@@ -624,16 +624,28 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder,
 	dev_priv->av_enc_map[pipe] = intel_encoder;
 	mutex_unlock(&dev_priv->av_mutex);
 
-	/* audio drivers expect pipe = -1 to indicate Non-MST cases */
-	if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
-		pipe = -1;
-
-	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
+	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
+		/* audio drivers expect pipe = -1 to indicate Non-MST cases */
+		if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
+			pipe = -1;
 		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
 						 (int) port, (int) pipe);
+	}
 
-	intel_lpe_audio_notify(dev_priv, connector->eld, port,
-			crtc_state->port_clock);
+	switch (intel_encoder->type) {
+	case INTEL_OUTPUT_HDMI:
+		intel_lpe_audio_notify(dev_priv, connector->eld, port, pipe,
+				       crtc_state->port_clock,
+				       false, 0);
+		break;
+	case INTEL_OUTPUT_DP:
+		intel_lpe_audio_notify(dev_priv, connector->eld, port, pipe,
+				       adjusted_mode->crtc_clock,
+				       true, crtc_state->port_clock);
+		break;
+	default:
+		break;
+	}
 }
 
 /**
@@ -660,15 +672,15 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
 	dev_priv->av_enc_map[pipe] = NULL;
 	mutex_unlock(&dev_priv->av_mutex);
 
-	/* audio drivers expect pipe = -1 to indicate Non-MST cases */
-	if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
-		pipe = -1;
-
-	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
+	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
+		/* audio drivers expect pipe = -1 to indicate Non-MST cases */
+		if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
+			pipe = -1;
 		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
 						 (int) port, (int) pipe);
+	}
 
-	intel_lpe_audio_notify(dev_priv, NULL, port, 0);
+	intel_lpe_audio_notify(dev_priv, NULL, port, pipe, 0, false, 0);
 }
 
 /**

+ 20 - 3
drivers/gpu/drm/i915/intel_lpe_audio.c

@@ -332,10 +332,12 @@ void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv)
  * Notify lpe audio driver of eld change.
  */
 void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
-			void *eld, int port, int tmds_clk_speed)
+			    void *eld, int port, int pipe, int tmds_clk_speed,
+			    bool dp_output, int link_rate)
 {
 	unsigned long irq_flags;
 	struct intel_hdmi_lpe_audio_pdata *pdata = NULL;
+	u32 audio_enable;
 
 	if (!HAS_LPE_AUDIO(dev_priv))
 		return;
@@ -345,23 +347,38 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
 
 	spin_lock_irqsave(&pdata->lpe_audio_slock, irq_flags);
 
+	audio_enable = I915_READ(VLV_AUD_PORT_EN_DBG(port));
+
 	if (eld != NULL) {
 		memcpy(pdata->eld.eld_data, eld,
 			HDMI_MAX_ELD_BYTES);
 		pdata->eld.port_id = port;
+		pdata->eld.pipe_id = pipe;
 		pdata->hdmi_connected = true;
 
+		pdata->dp_output = dp_output;
 		if (tmds_clk_speed)
 			pdata->tmds_clock_speed = tmds_clk_speed;
+		if (link_rate)
+			pdata->link_rate = link_rate;
+
+		/* Unmute the amp for both DP and HDMI */
+		I915_WRITE(VLV_AUD_PORT_EN_DBG(port),
+			   audio_enable & ~VLV_AMP_MUTE);
+
 	} else {
 		memset(pdata->eld.eld_data, 0,
 			HDMI_MAX_ELD_BYTES);
 		pdata->hdmi_connected = false;
+		pdata->dp_output = false;
+
+		/* Mute the amp for both DP and HDMI */
+		I915_WRITE(VLV_AUD_PORT_EN_DBG(port),
+			   audio_enable | VLV_AMP_MUTE);
 	}
 
 	if (pdata->notify_audio_lpe)
-		pdata->notify_audio_lpe(
-			(eld != NULL) ? &pdata->eld : NULL);
+		pdata->notify_audio_lpe(dev_priv->lpe_audio.platdev);
 	else
 		pdata->notify_pending = true;
 

+ 6 - 1
include/drm/intel_lpe_audio.h

@@ -27,10 +27,13 @@
 #include <linux/types.h>
 #include <linux/spinlock_types.h>
 
+struct platform_device;
+
 #define HDMI_MAX_ELD_BYTES	128
 
 struct intel_hdmi_lpe_audio_eld {
 	int port_id;
+	int pipe_id;
 	unsigned char eld_data[HDMI_MAX_ELD_BYTES];
 };
 
@@ -38,8 +41,10 @@ struct intel_hdmi_lpe_audio_pdata {
 	bool notify_pending;
 	int tmds_clock_speed;
 	bool hdmi_connected;
+	bool dp_output;
+	int link_rate;
 	struct intel_hdmi_lpe_audio_eld eld;
-	void (*notify_audio_lpe)(void *audio_ptr);
+	void (*notify_audio_lpe)(struct platform_device *pdev);
 	spinlock_t lpe_audio_slock;
 };
 

+ 147 - 26
sound/x86/intel_hdmi_audio.c

@@ -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);

+ 5 - 3
sound/x86/intel_hdmi_audio.h

@@ -44,7 +44,8 @@
 #define MAX_CAP_STREAMS		0
 #define HDMI_AUDIO_DRIVER	"hdmi-audio"
 
-#define INFO_FRAME_WORD1	0x000a0184
+#define HDMI_INFO_FRAME_WORD1	0x000a0184
+#define DP_INFO_FRAME_WORD1	0x00441b84
 #define FIFO_THRESHOLD		0xFE
 #define DMA_FIFO_THRESHOLD	0x7
 #define BYTES_PER_WORD		0x4
@@ -134,6 +135,7 @@ struct snd_intelhad {
 	struct		ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS];
 	struct		pcm_stream_info stream_info;
 	union otm_hdmi_eld_t	eeld;
+	bool dp_output;
 	enum		intel_had_aud_buf_type curr_buf;
 	int		valid_buf_cnt;
 	unsigned int	aes_bits;
@@ -156,8 +158,8 @@ struct had_ops {
 	void (*reset_audio)(u8 reset);
 	int (*prog_n)(u32 aud_samp_freq, u32 *n_param,
 			struct snd_intelhad *intelhaddata);
-	void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 n_param,
-			struct snd_intelhad *intelhaddata);
+	void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 link_rate,
+			 u32 n_param, struct snd_intelhad *intelhaddata);
 	int (*audio_ctrl)(struct snd_pcm_substream *substream,
 				struct snd_intelhad *intelhaddata);
 	void (*prog_dip)(struct snd_pcm_substream *substream,

+ 66 - 17
sound/x86/intel_hdmi_lpe_audio.c

@@ -48,6 +48,8 @@ struct hdmi_lpe_audio_ctx {
 	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;
@@ -187,6 +189,15 @@ static int hdmi_audio_write(u32 reg, u32 val)
 
 	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;
@@ -220,6 +231,16 @@ static int hdmi_audio_rmw(u32 reg, u32 val, u32 mask)
 	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);
@@ -249,7 +270,18 @@ static int hdmi_audio_get_caps(enum had_caps_list get_element,
 		/* 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;
@@ -407,15 +439,14 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static void notify_audio_lpe(void *audio_ptr)
+static void notify_audio_lpe(struct platform_device *pdev)
 {
-	struct hdmi_lpe_audio_ctx *ctx = get_hdmi_context();
-	struct intel_hdmi_lpe_audio_pdata *pdata = hlpe_pdev->dev.platform_data;
-	struct intel_hdmi_lpe_audio_eld *eld = audio_ptr;
+	struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
+	struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data;
 
 	if (pdata->hdmi_connected != true) {
 
-		dev_dbg(&hlpe_pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
+		dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
 			__func__);
 
 		if (hlpe_state == hdmi_connector_status_connected) {
@@ -426,10 +457,27 @@ static void notify_audio_lpe(void *audio_ptr)
 			mid_hdmi_audio_signal_event(
 				HAD_EVENT_HOT_UNPLUG);
 		} else
-			dev_dbg(&hlpe_pdev->dev, "%s: Already Unplugged!\n",
+			dev_dbg(&pdev->dev, "%s: Already Unplugged!\n",
 				__func__);
 
-	} else if (eld != NULL) {
+	} else {
+		struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld;
+
+		switch (eld->pipe_id) {
+		case 0:
+			ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
+			break;
+		case 1:
+			ctx->had_config_offset = AUDIO_HDMI_CONFIG_B;
+			break;
+		case 2:
+			ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
+			break;
+		default:
+			dev_dbg(&pdev->dev, "Invalid pipe %d\n",
+				eld->pipe_id);
+			break;
+		}
 
 		hdmi_set_eld(eld->eld_data);
 
@@ -437,15 +485,16 @@ static void notify_audio_lpe(void *audio_ptr)
 
 		hlpe_state = hdmi_connector_status_connected;
 
-		dev_dbg(&hlpe_pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
+		dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
 			__func__, eld->port_id,	pdata->tmds_clock_speed);
 
 		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
-		dev_dbg(&hlpe_pdev->dev, "%s: Event: NULL EDID!!\n", __func__);
+	}
 }
 
 /**
@@ -526,15 +575,15 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
 	ctx->mmio_start = mmio_start;
 	ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5;
 
-	if (pci_dev_present(cherryview_ids)) {
+	if (pci_dev_present(cherryview_ids))
 		dev_dbg(&hlpe_pdev->dev, "%s: Cherrytrail LPE - Detected\n",
 				__func__);
-		ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
-	} else {
+	else
 		dev_dbg(&hlpe_pdev->dev, "%s: Baytrail LPE - Assume\n",
 				__func__);
-		ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
-	}
+
+	/* assume pipe A as default */
+	ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
 
 	pdata = pdev->dev.platform_data;
 
@@ -556,7 +605,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
 	if (pdata->notify_pending) {
 
 		dev_dbg(&hlpe_pdev->dev, "%s: handle pending notification\n", __func__);
-		notify_audio_lpe(&pdata->eld);
+		notify_audio_lpe(pdev);
 		pdata->notify_pending = false;
 	}
 	spin_unlock_irqrestore(&pdata->lpe_audio_slock, flag_irq);

+ 29 - 0
sound/x86/intel_hdmi_lpe_audio.h

@@ -31,6 +31,10 @@
 #include <sound/control.h>
 #include <sound/pcm.h>
 
+#define AUD_CONFIG_VALID_BIT			(1<<9)
+#define AUD_CONFIG_DP_MODE			(1<<15)
+#define AUD_CONFIG_BLOCK_BIT			(1<<7)
+
 #define HMDI_LPE_AUDIO_DRIVER_NAME		"intel-hdmi-lpe-audio"
 #define HAD_MAX_DEVICES		1
 #define HAD_MIN_CHANNEL		2
@@ -68,6 +72,29 @@
 #define HAD_MAX_DIP_WORDS		16
 #define INTEL_HAD		"IntelHdmiLpeAudio"
 
+/* DP Link Rates */
+#define DP_2_7_GHZ			270000
+#define DP_1_62_GHZ			162000
+
+/* Maud Values */
+#define AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL		1988
+#define AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL		2740
+#define AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL		2982
+#define AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL		5480
+#define AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL		5965
+#define AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL		10961
+#define HAD_MAX_RATE_DP_2_7_MAUD_VAL			11930
+#define AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL		3314
+#define AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL		4567
+#define AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL		4971
+#define AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL		9134
+#define AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL		9942
+#define AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL		18268
+#define HAD_MAX_RATE_DP_1_62_MAUD_VAL			19884
+
+/* Naud Value */
+#define DP_NAUD_VAL					32768
+
 /* _AUD_CONFIG register MASK */
 #define AUD_CONFIG_MASK_UNDERRUN	0xC0000000
 #define AUD_CONFIG_MASK_SRDBG		0x00000002
@@ -618,6 +645,8 @@ enum hdmi_connector_status {
 enum had_caps_list {
 	HAD_GET_ELD = 1,
 	HAD_GET_DISPLAY_RATE,
+	HAD_GET_DP_OUTPUT,
+	HAD_GET_LINK_RATE,
 	HAD_SET_ENABLE_AUDIO,
 	HAD_SET_DISABLE_AUDIO,
 	HAD_SET_ENABLE_AUDIO_INT,