mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 18:09:57 +00:00
ALSA: hda - set intel audio clock to a proper value
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 proper value if it is set incorrectly. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=188411 Signed-off-by: Libin Yang <libin.yang@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
dde5bff541
commit
1f9d3d9869
1 changed files with 95 additions and 0 deletions
|
@ -540,6 +540,98 @@ static void bxt_reduce_dma_latency(struct azx *chip)
|
||||||
azx_writel(chip, VS_EM4L, val);
|
azx_writel(chip, VS_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)
|
||||||
|
{
|
||||||
|
struct hdac_bus *bus = azx_bus(chip);
|
||||||
|
static int preferred_bits[] = { 2, 3, 1, 4, 5 };
|
||||||
|
u32 val, t;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCAP);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(preferred_bits); i++) {
|
||||||
|
t = preferred_bits[i];
|
||||||
|
if (val & (1 << t))
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_warn(chip->card->dev, "set audio clock frequency to 6MHz");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int intel_ml_lctl_set_power(struct azx *chip, int state)
|
||||||
|
{
|
||||||
|
struct hdac_bus *bus = azx_bus(chip);
|
||||||
|
u32 val;
|
||||||
|
int timeout;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the codecs are sharing the first link setting by default
|
||||||
|
* If other links are enabled for stream, they need similar fix
|
||||||
|
*/
|
||||||
|
val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
|
||||||
|
val &= ~AZX_MLCTL_SPA;
|
||||||
|
val |= state << AZX_MLCTL_SPA_SHIFT;
|
||||||
|
writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
|
||||||
|
/* wait for CPA */
|
||||||
|
timeout = 50;
|
||||||
|
while (timeout) {
|
||||||
|
if (((readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL)) &
|
||||||
|
AZX_MLCTL_CPA) == (state << AZX_MLCTL_CPA_SHIFT))
|
||||||
|
return 0;
|
||||||
|
timeout--;
|
||||||
|
udelay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_init_lctl(struct azx *chip)
|
||||||
|
{
|
||||||
|
struct hdac_bus *bus = azx_bus(chip);
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* 0. check lctl register value is correct or not */
|
||||||
|
val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
|
||||||
|
/* if SCF is already set, let's use it */
|
||||||
|
if ((val & ML_LCTL_SCF_MASK) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Before operating 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 */
|
||||||
|
ret = intel_ml_lctl_set_power(chip, 0);
|
||||||
|
udelay(100);
|
||||||
|
if (ret)
|
||||||
|
goto set_spa;
|
||||||
|
|
||||||
|
/* 2. update SCF to select a properly audio clock*/
|
||||||
|
val &= ~ML_LCTL_SCF_MASK;
|
||||||
|
val |= intel_get_lctl_scf(chip);
|
||||||
|
writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
|
||||||
|
|
||||||
|
set_spa:
|
||||||
|
/* 4. turn link up: set SPA to 1 and wait CPA to 1 */
|
||||||
|
intel_ml_lctl_set_power(chip, 1);
|
||||||
|
udelay(100);
|
||||||
|
}
|
||||||
|
|
||||||
static void hda_intel_init_chip(struct azx *chip, bool full_reset)
|
static void hda_intel_init_chip(struct azx *chip, bool full_reset)
|
||||||
{
|
{
|
||||||
struct hdac_bus *bus = azx_bus(chip);
|
struct hdac_bus *bus = azx_bus(chip);
|
||||||
|
@ -565,6 +657,9 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
|
||||||
/* reduce dma latency to avoid noise */
|
/* reduce dma latency to avoid noise */
|
||||||
if (IS_BXT(pci))
|
if (IS_BXT(pci))
|
||||||
bxt_reduce_dma_latency(chip);
|
bxt_reduce_dma_latency(chip);
|
||||||
|
|
||||||
|
if (bus->mlcap != NULL)
|
||||||
|
intel_init_lctl(chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calculate runtime delay from LPIB */
|
/* calculate runtime delay from LPIB */
|
||||||
|
|
Loading…
Reference in a new issue