[PATCH-V2 1/2] drm/i915: add callback to enable/disable codec wakeup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: "Lu, Han" <han.lu@xxxxxxxxx>

In SKL, HDMI/DP codec and PCH HD Audio Controller are in different
power wells, so it's necessary to reset display audio codecs when
power well on, otherwise display audio codecs will disappear when
resume from low power state.
The reset step when power on is:
    enable codec wakeup -> azx_init_chip() -> disable codec wakeup

The callback is defined in drivers/gpu/drm/i915/.
The caller is in sound/pci/hda/.

Signed-off-by: Lu, Han <han.lu@xxxxxxxxx>

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f3c77ca..efcf900 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1143,6 +1143,11 @@ struct i915_power_domains {
 	struct i915_power_well *power_wells;
 };
 
+struct i915_audio_priv {
+	struct mutex lock;
+	int audio_power_cnt;
+};
+
 #define MAX_L3_SLICES 2
 struct intel_l3_parity {
 	u32 *remap_info[MAX_L3_SLICES];
@@ -1757,6 +1762,8 @@ struct drm_i915_private {
 	/* hda/i915 audio component */
 	bool audio_component_registered;
 
+	struct i915_audio_priv audio_priv;
+
 	uint32_t hw_context_size;
 	struct list_head context_list;
 
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 36805b6..efdccaf 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -6881,6 +6881,9 @@ enum skl_disp_power_wells {
 #define   AUDIO_CP_READY(trans)		((1 << 1) << ((trans) * 4))
 #define   AUDIO_ELD_VALID(trans)	((1 << 0) << ((trans) * 4))
 
+#define HSW_AUD_CHICKENBIT			0x65f10
+#define   AUD_CODEC_WAKE_SIGNAL			(1 << 15)
+
 /* HSW Power Wells */
 #define HSW_PWR_WELL_BIOS			0x45400 /* CTL1 */
 #define HSW_PWR_WELL_DRIVER			0x45404 /* CTL2 */
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index f72e93a..e0cf2b9 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -448,6 +448,9 @@ void intel_audio_codec_disable(struct intel_encoder *encoder)
 void intel_init_audio(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct i915_audio_priv *audio_priv = &dev_priv->audio_priv;
+
+	mutex_init(&audio_priv->lock);
 
 	if (IS_G4X(dev)) {
 		dev_priv->display.audio_codec_enable = g4x_audio_codec_enable;
@@ -474,6 +477,60 @@ static void i915_audio_component_put_power(struct device *dev)
 	intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
 }
 
+static void i915_audio_component_enable_codec_wakeup(struct device *dev)
+{
+	struct drm_i915_private *dev_priv = dev_to_i915(dev);
+	struct i915_audio_priv *audio_priv = &dev_priv->audio_priv;
+	u32 tmp;
+
+	if (!IS_SKYLAKE(dev_priv->dev))
+		return;
+
+	mutex_lock(&audio_priv->lock);
+
+	/* SKL need reset the CHICKENBIT bit 15 after power on codec */
+	if (audio_priv->audio_power_cnt == 0) {
+		tmp = I915_READ(HSW_AUD_CHICKENBIT);
+		tmp &= ~AUD_CODEC_WAKE_SIGNAL;
+		I915_WRITE(HSW_AUD_CHICKENBIT, tmp);
+		mdelay(1);
+
+		tmp = I915_READ(HSW_AUD_CHICKENBIT);
+		tmp |= AUD_CODEC_WAKE_SIGNAL;
+		I915_WRITE(HSW_AUD_CHICKENBIT, tmp);
+		mdelay(1);
+	}
+
+	audio_priv->audio_power_cnt++;
+
+	mutex_unlock(&audio_priv->lock);
+}
+
+static void i915_audio_component_disable_codec_wakeup(struct device *dev)
+{
+	struct drm_i915_private *dev_priv = dev_to_i915(dev);
+	struct i915_audio_priv *audio_priv = &dev_priv->audio_priv;
+	u32 tmp;
+
+	if (!IS_SKYLAKE(dev_priv->dev))
+		return;
+
+	mutex_lock(&audio_priv->lock);
+
+	audio_priv->audio_power_cnt--;
+	if (audio_priv->audio_power_cnt < 0)
+		dev_warn(dev, "audio_power_cnt(%d) < 0\n",
+				audio_priv->audio_power_cnt);
+
+	/* SKL need clear the CHICKENBIT bit 15 after codec detected */
+	tmp = I915_READ(HSW_AUD_CHICKENBIT);
+	tmp &= ~AUD_CODEC_WAKE_SIGNAL;
+	I915_WRITE(HSW_AUD_CHICKENBIT, tmp);
+	mdelay(1);
+
+	mutex_unlock(&audio_priv->lock);
+}
+
 /* Get CDCLK in kHz  */
 static int i915_audio_component_get_cdclk_freq(struct device *dev)
 {
@@ -495,6 +552,8 @@ static const struct i915_audio_component_ops i915_audio_component_ops = {
 	.owner		= THIS_MODULE,
 	.get_power	= i915_audio_component_get_power,
 	.put_power	= i915_audio_component_put_power,
+	.enable_codec_wakeup	= i915_audio_component_enable_codec_wakeup,
+	.disable_codec_wakeup	= i915_audio_component_disable_codec_wakeup,
 	.get_cdclk_freq	= i915_audio_component_get_cdclk_freq,
 };
 
diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
index 3e2f22e..1d57aae 100644
--- a/include/drm/i915_component.h
+++ b/include/drm/i915_component.h
@@ -31,6 +31,8 @@ struct i915_audio_component {
 		struct module *owner;
 		void (*get_power)(struct device *);
 		void (*put_power)(struct device *);
+		void (*enable_codec_wakeup)(struct device *);
+		void (*disable_codec_wakeup)(struct device *);
 		int (*get_cdclk_freq)(struct device *);
 	} *ops;
 };
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/intel-gfx





[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux