mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-23 01:40:30 +00:00
ASoC: Intel: Add PM support to the HSW/BDW DSP core.
Add support for PM wake, sleep and stall calls to the core HSW/BDW driver. This includes reworking the reset and boot code and adding new calls for setting D3/D0 state. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
d96c53a193
commit
6b7b4b8941
@ -247,8 +247,67 @@ static irqreturn_t hsw_irq(int irq, void *context)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hsw_boot(struct sst_dsp *sst)
|
||||
static void hsw_set_dsp_D3(struct sst_dsp *sst)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* switch off audio PLL, DRAM & IRAM blocks */
|
||||
val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
val |= SST_VDRTCL0_APLLSE_MASK | SST_VDRTCL0_DSRAMPGE_MASK |
|
||||
SST_VDRTCL0_ISRAMPGE_MASK;
|
||||
writel(val, sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
|
||||
/* Set D3 state */
|
||||
val = readl(sst->addr.pci_cfg + SST_PMCS);
|
||||
val |= SST_PMCS_PS_MASK;
|
||||
writel(val, sst->addr.pci_cfg + SST_PMCS);
|
||||
}
|
||||
|
||||
static void hsw_reset(struct sst_dsp *sst)
|
||||
{
|
||||
/* put DSP into reset and stall */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
||||
SST_CSR_RST | SST_CSR_STALL,
|
||||
SST_CSR_RST | SST_CSR_STALL);
|
||||
|
||||
/* keep in reset for 10ms */
|
||||
mdelay(10);
|
||||
|
||||
/* take DSP out of reset and keep stalled for FW loading */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
||||
SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
|
||||
}
|
||||
|
||||
static int hsw_set_dsp_D0(struct sst_dsp *sst)
|
||||
{
|
||||
int tries = 10;
|
||||
u32 reg;
|
||||
|
||||
/* Set D0 state */
|
||||
reg = readl(sst->addr.pci_cfg + SST_PMCS);
|
||||
reg &= ~SST_PMCS_PS_MASK;
|
||||
writel(reg, sst->addr.pci_cfg + SST_PMCS);
|
||||
|
||||
/* check that ADSP shim is enabled */
|
||||
while (tries--) {
|
||||
reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK;
|
||||
if (reg == 0)
|
||||
goto finish;
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
|
||||
finish:
|
||||
hsw_reset(sst);
|
||||
|
||||
/* switch on audio PLL, DRAM & IRAM blocks */
|
||||
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
reg &= ~(SST_VDRTCL0_APLLSE_MASK | SST_VDRTCL0_DSRAMPGE_MASK |
|
||||
SST_VDRTCL0_ISRAMPGE_MASK);
|
||||
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
|
||||
/* 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);
|
||||
@ -267,30 +326,73 @@ static void hsw_boot(struct sst_dsp *sst)
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
|
||||
SST_CSR2_SDFD_SSP1);
|
||||
|
||||
/* enable DMA engine 0,1 all channels to access host memory */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_HMDC,
|
||||
SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff),
|
||||
SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff));
|
||||
/* set on-demond mode on engine 0,1 for all channels */
|
||||
sst_dsp_shim_update_bits(sst, SST_HMDC,
|
||||
SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH,
|
||||
SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH);
|
||||
|
||||
/* Enable Interrupt from both sides */
|
||||
sst_dsp_shim_update_bits(sst, SST_IMRX, (SST_IMRX_BUSY | SST_IMRX_DONE),
|
||||
0x0);
|
||||
sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY |
|
||||
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);
|
||||
|
||||
/* disable all clock gating */
|
||||
writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hsw_boot(struct sst_dsp *sst)
|
||||
{
|
||||
/* set oportunistic mode on engine 0,1 for all channels */
|
||||
sst_dsp_shim_update_bits(sst, SST_HMDC,
|
||||
SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, 0);
|
||||
|
||||
/* set DSP to RUN */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0);
|
||||
}
|
||||
|
||||
static void hsw_reset(struct sst_dsp *sst)
|
||||
static void hsw_stall(struct sst_dsp *sst)
|
||||
{
|
||||
/* stall DSP */
|
||||
sst_dsp_shim_update_bits(sst, SST_CSR,
|
||||
SST_CSR_24MHZ_LPCS | SST_CSR_STALL,
|
||||
SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
|
||||
}
|
||||
|
||||
static void hsw_sleep(struct sst_dsp *sst)
|
||||
{
|
||||
dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n");
|
||||
|
||||
/* put DSP into reset and stall */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
||||
SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_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);
|
||||
|
||||
/* keep in reset for 10ms */
|
||||
mdelay(10);
|
||||
hsw_set_dsp_D3(sst);
|
||||
dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n");
|
||||
}
|
||||
|
||||
/* take DSP out of reset and keep stalled for FW loading */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
||||
SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
|
||||
static int hsw_wake(struct sst_dsp *sst)
|
||||
{
|
||||
int ret;
|
||||
|
||||
dev_dbg(sst->dev, "HSW_PM dsp runtime resume\n");
|
||||
|
||||
ret = hsw_set_dsp_D0(sst);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_dbg(sst->dev, "HSW_PM dsp runtime resume exit\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sst_adsp_memregion {
|
||||
@ -431,27 +533,6 @@ static struct sst_block_ops sst_hsw_ops = {
|
||||
.disable = hsw_block_disable,
|
||||
};
|
||||
|
||||
static int hsw_enable_shim(struct sst_dsp *sst)
|
||||
{
|
||||
int tries = 10;
|
||||
u32 reg;
|
||||
|
||||
/* enable shim */
|
||||
reg = readl(sst->addr.pci_cfg + SST_SHIM_PM_REG);
|
||||
writel(reg & ~0x3, sst->addr.pci_cfg + SST_SHIM_PM_REG);
|
||||
|
||||
/* check that ADSP shim is enabled */
|
||||
while (tries--) {
|
||||
reg = sst_dsp_shim_read_unlocked(sst, SST_CSR);
|
||||
if (reg != 0xffffffff)
|
||||
return 0;
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||
{
|
||||
const struct sst_adsp_memregion *region;
|
||||
@ -490,7 +571,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||
}
|
||||
|
||||
/* enable the DSP SHIM */
|
||||
ret = hsw_enable_shim(sst);
|
||||
ret = hsw_set_dsp_D0(sst);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n");
|
||||
return ret;
|
||||
@ -500,10 +581,6 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable Interrupt from both sides */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, 0x3, 0x0);
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_IMRD,
|
||||
(0x3 | 0x1 << 16 | 0x3 << 21), 0x0);
|
||||
|
||||
/* register DSP memory blocks - ideally we should get this from ACPI */
|
||||
for (i = 0; i < region_count; i++) {
|
||||
@ -535,6 +612,9 @@ static void hsw_free(struct sst_dsp *sst)
|
||||
struct sst_ops haswell_ops = {
|
||||
.reset = hsw_reset,
|
||||
.boot = hsw_boot,
|
||||
.stall = hsw_stall,
|
||||
.wake = hsw_wake,
|
||||
.sleep = hsw_sleep,
|
||||
.write = sst_shim32_write,
|
||||
.read = sst_shim32_read,
|
||||
.write64 = sst_shim32_write64,
|
||||
|
Loading…
Reference in New Issue
Block a user