[alsa-devel] [PATCH] ALSA: hda - set intel audio clock to a properly value
libin.yang at intel.com
libin.yang at intel.com
Tue Mar 7 07:20:22 CET 2017
From: Libin Yang <libin.yang at intel.com>
On some Intel platforms, the audio clock may not be set correctly
with initial setting. This will cause the audio playback/capture
rates wrong.
This patch checks the audio clock setting and will set it to a
properly value if it is not set correct.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=188411
Signed-off-by: Libin Yang <libin.yang at intel.com>
---
include/sound/hda_register.h | 12 +++--
sound/hda/ext/hdac_ext_controller.c | 6 +--
sound/pci/hda/hda_intel.c | 91 +++++++++++++++++++++++++++++++++++++
3 files changed, 103 insertions(+), 6 deletions(-)
diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h
index 0013063..7ea16cb 100644
--- a/include/sound/hda_register.h
+++ b/include/sound/hda_register.h
@@ -227,6 +227,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_REG_PPLCLLPU 0xC
/* registers for Multiple Links Capability Structure */
+/* Multiple Links Capability */
+#define AZX_REG_ML_CAP_BASE 0xc00
#define AZX_ML_CAP_ID 0x2
#define AZX_REG_ML_MLCH 0x00
#define AZX_REG_ML_MLCD 0x04
@@ -243,9 +245,13 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_REG_ML_LOUTPAY 0x20
#define AZX_REG_ML_LINPAY 0x30
-#define AZX_MLCTL_SPA (1<<16)
-#define AZX_MLCTL_CPA 23
-
+#define AZX_REG_ML_LCAPx(x) (AZX_REG_ML_CAP_BASE + (0x40 + 0x40 * x))
+#define AZX_REG_ML_LCTLx(x) (AZX_REG_ML_CAP_BASE + (0x44 + 0x40 * x))
+#define ML_LCTL_SCF_MASK 0xF
+#define AZX_MLCTL_SPA (0x1 << 16)
+#define AZX_MLCTL_CPA (0x1 << 23)
+#define AZX_MLCTL_SPA_SHIFT 16
+#define AZX_MLCTL_CPA_SHIFT 23
/* registers for DMA Resume Capability Structure */
#define AZX_DRSM_CAP_ID 0x5
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 2614691..84f3b81 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -171,7 +171,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
{
int timeout;
u32 val;
- int mask = (1 << AZX_MLCTL_CPA);
+ int mask = (1 << AZX_MLCTL_CPA_SHIFT);
udelay(3);
timeout = 150;
@@ -179,10 +179,10 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
do {
val = readl(link->ml_addr + AZX_REG_ML_LCTL);
if (enable) {
- if (((val & mask) >> AZX_MLCTL_CPA))
+ if (((val & mask) >> AZX_MLCTL_CPA_SHIFT))
return 0;
} else {
- if (!((val & mask) >> AZX_MLCTL_CPA))
+ if (!((val & mask) >> AZX_MLCTL_CPA_SHIFT))
return 0;
}
udelay(3);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c8256a8..017f64f 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -539,6 +539,94 @@ static void bxt_reduce_dma_latency(struct azx *chip)
azx_writel(chip, SKL_EM4L, val);
}
+/*
+ * ML_LCAP bits:
+ * bit 0: 6 MHz Supported
+ * bit 1: 12 MHz Supported
+ * bit 2: 24 MHz Supported
+ * bit 3: 48 MHz Supported
+ * bit 4: 96 MHz Supported
+ * bit 5: 192 MHz Supported
+ */
+static int intel_get_lctl_scf(struct azx *chip)
+{
+ u32 val;
+
+ val = azx_readl(chip, ML_LCAPx(0));
+
+ if (val & (1 << 2))
+ return 2;
+ else if (val & (1 << 3))
+ return 3;
+ else if (val & (1 << 1))
+ return 1;
+ else if (val & (1 << 4))
+ return 4;
+ else if (val & (1 << 5))
+ return 5;
+
+ dev_warn(chip->card->dev, "set audio clock frequency to 6MHz");
+ return 0;
+}
+
+static void intel_init_lctl(struct azx *chip)
+{
+ u32 val;
+ int timeout;
+
+ /* 0. check lctl register value is correct or not */
+ /* the codecs are sharing the first link setting by default */
+ val = azx_readl(chip, ML_LCTLx(0));
+ /* if SCF is already set, let's use it */
+ if ((val & ML_LCTL_SCF_MASK) != 0)
+ return;
+
+ /*
+ * Before operatiing on SPA, CPA must match SPA.
+ * Any deviation may result in undefined behavior.
+ */
+ if (((val & AZX_MLCTL_SPA) >> AZX_MLCTL_SPA_SHIFT) ^
+ ((val & AZX_MLCTL_CPA) >> AZX_MLCTL_CPA_SHIFT))
+ return;
+
+ /* 1. turn link down: set SPA to 0 and wait CPA to 0 */
+ val = azx_readl(chip, ML_LCTLx(0));
+ val &= ~AZX_MLCTL_SPA;
+ azx_writel(chip, ML_LCTLx(0), val);
+ /* wait for CPA */
+ timeout = 50;
+ while (timeout) {
+ if ((azx_readl(chip, ML_LCTLx(0)) & AZX_MLCTL_CPA) == 0)
+ break;
+ timeout--;
+ udelay(10);
+ }
+ if (!timeout)
+ goto SET_SPA;
+ /* need add 100ns delay for hardware ready */
+ udelay(100);
+
+ /* 2. update SCF to select a properly audio clock*/
+ val &= ~ML_LCTL_SCF_MASK;
+ val |= intel_get_lctl_scf(chip);
+ azx_writel(chip, ML_LCTLx(0), val);
+
+SET_SPA:
+ /* 4. turn link up: set SPA to 1 and wait CPA to 1 */
+ val = azx_readl(chip, ML_LCTLx(0));
+ val |= AZX_MLCTL_SPA;
+ azx_writel(chip, ML_LCTLx(0), val);
+ timeout = 50;
+ while (timeout) {
+ if ((azx_readl(chip, ML_LCTLx(0)) & AZX_MLCTL_CPA) != 0)
+ break;
+ timeout--;
+ udelay(10);
+ }
+ /* need add 100ns delay for hardware ready */
+ udelay(100);
+}
+
static void hda_intel_init_chip(struct azx *chip, bool full_reset)
{
struct hdac_bus *bus = azx_bus(chip);
@@ -564,6 +652,9 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
/* reduce dma latency to avoid noise */
if (IS_BXT(pci))
bxt_reduce_dma_latency(chip);
+
+ if (IS_SKL_PLUS(pci))
+ intel_init_lctl(chip);
}
/* calculate runtime delay from LPIB */
--
2.7.4
More information about the Alsa-devel
mailing list