Commit 15454955 authored by Cezary Rojewski's avatar Cezary Rojewski Committed by Mark Brown

ASoC: Intel: haswell: Fix power transition refactor

While addressing existing power-cycle limitations for
sound/soc/intel/haswell solution, change brings regression for standard
audio userspace flows e.g.: when using PulseAudio.

Occasional sound-card initialization fail is still better than
permanent audio distortions, so revert the change.

Fixes: 8ec7d604 ("ASoC: Intel: haswell: Power transition refactor")
Reported-by: default avatarChristian Bundy <christianbundy@fraction.io>
Signed-off-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20200901153041.14771-1-cezary.rojewski@intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 2569231d
...@@ -243,92 +243,45 @@ static irqreturn_t hsw_irq(int irq, void *context) ...@@ -243,92 +243,45 @@ static irqreturn_t hsw_irq(int irq, void *context)
return ret; return ret;
} }
#define CSR_DEFAULT_VALUE 0x8480040E
#define ISC_DEFAULT_VALUE 0x0
#define ISD_DEFAULT_VALUE 0x0
#define IMC_DEFAULT_VALUE 0x7FFF0003
#define IMD_DEFAULT_VALUE 0x7FFF0003
#define IPCC_DEFAULT_VALUE 0x0
#define IPCD_DEFAULT_VALUE 0x0
#define CLKCTL_DEFAULT_VALUE 0x7FF
#define CSR2_DEFAULT_VALUE 0x0
#define LTR_CTRL_DEFAULT_VALUE 0x0
#define HMD_CTRL_DEFAULT_VALUE 0x0
static void hsw_set_shim_defaults(struct sst_dsp *sst)
{
sst_dsp_shim_write_unlocked(sst, SST_CSR, CSR_DEFAULT_VALUE);
sst_dsp_shim_write_unlocked(sst, SST_ISRX, ISC_DEFAULT_VALUE);
sst_dsp_shim_write_unlocked(sst, SST_ISRD, ISD_DEFAULT_VALUE);
sst_dsp_shim_write_unlocked(sst, SST_IMRX, IMC_DEFAULT_VALUE);
sst_dsp_shim_write_unlocked(sst, SST_IMRD, IMD_DEFAULT_VALUE);
sst_dsp_shim_write_unlocked(sst, SST_IPCX, IPCC_DEFAULT_VALUE);
sst_dsp_shim_write_unlocked(sst, SST_IPCD, IPCD_DEFAULT_VALUE);
sst_dsp_shim_write_unlocked(sst, SST_CLKCTL, CLKCTL_DEFAULT_VALUE);
sst_dsp_shim_write_unlocked(sst, SST_CSR2, CSR2_DEFAULT_VALUE);
sst_dsp_shim_write_unlocked(sst, SST_LTRC, LTR_CTRL_DEFAULT_VALUE);
sst_dsp_shim_write_unlocked(sst, SST_HMDC, HMD_CTRL_DEFAULT_VALUE);
}
/* all clock-gating minus DCLCGE and DTCGE */
#define SST_VDRTCL2_CG_OTHER 0xB7D
static void hsw_set_dsp_D3(struct sst_dsp *sst) static void hsw_set_dsp_D3(struct sst_dsp *sst)
{ {
u32 val;
u32 reg; u32 reg;
/* disable clock core gating */ /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
reg &= ~(SST_VDRTCL2_DCLCGE); reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
/* stall, reset and set 24MHz XOSC */ /* enable power gating and switch off DRAM & IRAM blocks */
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
SST_CSR_24MHZ_LPCS | SST_CSR_STALL | SST_CSR_RST, val |= SST_VDRTCL0_DSRAMPGE_MASK |
SST_CSR_24MHZ_LPCS | SST_CSR_STALL | SST_CSR_RST); SST_VDRTCL0_ISRAMPGE_MASK;
val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD);
/* DRAM power gating all */ writel(val, sst->addr.pci_cfg + SST_VDRTCTL0);
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
reg |= SST_VDRTCL0_ISRAMPGE_MASK |
SST_VDRTCL0_DSRAMPGE_MASK;
reg &= ~(SST_VDRTCL0_D3SRAMPGD);
reg |= SST_VDRTCL0_D3PGD;
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
udelay(50);
/* PLL shutdown enable */ /* switch off audio PLL */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
reg |= SST_VDRTCL2_APLLSE_MASK; val |= SST_VDRTCL2_APLLSE_MASK;
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
/* disable MCLK */ /* disable MCLK(clkctl.smos = 0) */
sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL, sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
SST_CLKCTL_MASK, 0); SST_CLKCTL_MASK, 0);
/* switch clock gating */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
reg |= SST_VDRTCL2_CG_OTHER;
reg &= ~(SST_VDRTCL2_DTCGE);
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
/* enable DTCGE separatelly */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
reg |= SST_VDRTCL2_DTCGE;
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
/* set shim defaults */ /* Set D3 state, delay 50 us */
hsw_set_shim_defaults(sst); val = readl(sst->addr.pci_cfg + SST_PMCS);
val |= SST_PMCS_PS_MASK;
/* set D3 */ writel(val, sst->addr.pci_cfg + SST_PMCS);
reg = readl(sst->addr.pci_cfg + SST_PMCS);
reg |= SST_PMCS_PS_MASK;
writel(reg, sst->addr.pci_cfg + SST_PMCS);
udelay(50); udelay(50);
/* enable clock core gating */ /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
reg |= SST_VDRTCL2_DCLCGE; reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
udelay(50); udelay(50);
} }
static void hsw_reset(struct sst_dsp *sst) static void hsw_reset(struct sst_dsp *sst)
...@@ -346,62 +299,75 @@ static void hsw_reset(struct sst_dsp *sst) ...@@ -346,62 +299,75 @@ static void hsw_reset(struct sst_dsp *sst)
SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL); SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
} }
/* recommended CSR state for power-up */
#define SST_CSR_D0_MASK (0x18A09C0C | SST_CSR_DCS_MASK)
static int hsw_set_dsp_D0(struct sst_dsp *sst) static int hsw_set_dsp_D0(struct sst_dsp *sst)
{ {
u32 reg; int tries = 10;
u32 reg, fw_dump_bit;
/* disable clock core gating */ /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
reg &= ~(SST_VDRTCL2_DCLCGE); reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
/* switch clock gating */ /* Disable D3PG (VDRTCTL0.D3PGD = 1) */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
reg |= SST_VDRTCL2_CG_OTHER; reg |= SST_VDRTCL0_D3PGD;
reg &= ~(SST_VDRTCL2_DTCGE); writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
/* set D0 */ /* Set D0 state */
reg = readl(sst->addr.pci_cfg + SST_PMCS); reg = readl(sst->addr.pci_cfg + SST_PMCS);
reg &= ~(SST_PMCS_PS_MASK); reg &= ~SST_PMCS_PS_MASK;
writel(reg, sst->addr.pci_cfg + SST_PMCS); writel(reg, sst->addr.pci_cfg + SST_PMCS);
/* DRAM power gating none */ /* check that ADSP shim is enabled */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); while (tries--) {
reg &= ~(SST_VDRTCL0_ISRAMPGE_MASK | reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK;
SST_VDRTCL0_DSRAMPGE_MASK); if (reg == 0)
reg |= SST_VDRTCL0_D3SRAMPGD; goto finish;
reg |= SST_VDRTCL0_D3PGD;
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0); msleep(1);
mdelay(10); }
return -ENODEV;
/* set shim defaults */ finish:
hsw_set_shim_defaults(sst); /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
/* stall DSP core, set clk to 192/96Mhz */
sst_dsp_shim_update_bits_unlocked(sst,
SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK,
SST_CSR_STALL | SST_CSR_DCS(4));
/* restore MCLK */ /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */
sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL, sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
SST_CLKCTL_MASK, SST_CLKCTL_MASK); SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
/* PLL shutdown disable */ /* Stall and reset core, set CSR */
hsw_reset(sst);
/* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
reg &= ~(SST_VDRTCL2_APLLSE_MASK); reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
SST_CSR_D0_MASK, SST_CSR_SBCS0 | SST_CSR_SBCS1 |
SST_CSR_STALL | SST_CSR_DCS(4));
udelay(50); udelay(50);
/* enable clock core gating */ /* switch on audio PLL */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
reg |= SST_VDRTCL2_DCLCGE; reg &= ~SST_VDRTCL2_APLLSE_MASK;
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
/* clear reset */ /* set default power gating control, enable power gating control for all blocks. that is,
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_RST, 0); can't be accessed, please enable each block before accessing. */
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
/* for D0, always enable the block(DSRAM[0]) used for FW dump */
fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
/* disable DMA finish function for SSP0 & SSP1 */ /* disable DMA finish function for SSP0 & SSP1 */
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1, sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
...@@ -418,6 +384,12 @@ static int hsw_set_dsp_D0(struct sst_dsp *sst) ...@@ -418,6 +384,12 @@ static int hsw_set_dsp_D0(struct sst_dsp *sst)
sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY | sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY |
SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0); SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0);
/* clear IPC registers */
sst_dsp_shim_write(sst, SST_IPCX, 0x0);
sst_dsp_shim_write(sst, SST_IPCD, 0x0);
sst_dsp_shim_write(sst, 0x80, 0x6);
sst_dsp_shim_write(sst, 0xe0, 0x300a);
return 0; return 0;
} }
...@@ -443,6 +415,11 @@ static void hsw_sleep(struct sst_dsp *sst) ...@@ -443,6 +415,11 @@ static void hsw_sleep(struct sst_dsp *sst)
{ {
dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n"); dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n");
/* put DSP into reset and stall */
sst_dsp_shim_update_bits(sst, SST_CSR,
SST_CSR_24MHZ_LPCS | SST_CSR_RST | SST_CSR_STALL,
SST_CSR_RST | SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
hsw_set_dsp_D3(sst); hsw_set_dsp_D3(sst);
dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n"); dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n");
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment