mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-10 19:43:29 +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;
|
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 */
|
/* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
|
||||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
||||||
SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
|
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_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
|
||||||
SST_CSR2_SDFD_SSP1);
|
SST_CSR2_SDFD_SSP1);
|
||||||
|
|
||||||
/* enable DMA engine 0,1 all channels to access host memory */
|
/* set on-demond mode on engine 0,1 for all channels */
|
||||||
sst_dsp_shim_update_bits_unlocked(sst, SST_HMDC,
|
sst_dsp_shim_update_bits(sst, SST_HMDC,
|
||||||
SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff),
|
SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH,
|
||||||
SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff));
|
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 */
|
/* disable all clock gating */
|
||||||
writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2);
|
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 */
|
/* set DSP to RUN */
|
||||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0);
|
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 */
|
/* put DSP into reset and stall */
|
||||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
sst_dsp_shim_update_bits(sst, SST_CSR,
|
||||||
SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_STALL);
|
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 */
|
hsw_set_dsp_D3(sst);
|
||||||
mdelay(10);
|
dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* take DSP out of reset and keep stalled for FW loading */
|
static int hsw_wake(struct sst_dsp *sst)
|
||||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
{
|
||||||
SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
|
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 {
|
struct sst_adsp_memregion {
|
||||||
@ -431,27 +533,6 @@ static struct sst_block_ops sst_hsw_ops = {
|
|||||||
.disable = hsw_block_disable,
|
.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)
|
static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||||
{
|
{
|
||||||
const struct sst_adsp_memregion *region;
|
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 */
|
/* enable the DSP SHIM */
|
||||||
ret = hsw_enable_shim(sst);
|
ret = hsw_set_dsp_D0(sst);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n");
|
dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n");
|
||||||
return ret;
|
return ret;
|
||||||
@ -500,10 +581,6 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return 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 */
|
/* register DSP memory blocks - ideally we should get this from ACPI */
|
||||||
for (i = 0; i < region_count; i++) {
|
for (i = 0; i < region_count; i++) {
|
||||||
@ -535,6 +612,9 @@ static void hsw_free(struct sst_dsp *sst)
|
|||||||
struct sst_ops haswell_ops = {
|
struct sst_ops haswell_ops = {
|
||||||
.reset = hsw_reset,
|
.reset = hsw_reset,
|
||||||
.boot = hsw_boot,
|
.boot = hsw_boot,
|
||||||
|
.stall = hsw_stall,
|
||||||
|
.wake = hsw_wake,
|
||||||
|
.sleep = hsw_sleep,
|
||||||
.write = sst_shim32_write,
|
.write = sst_shim32_write,
|
||||||
.read = sst_shim32_read,
|
.read = sst_shim32_read,
|
||||||
.write64 = sst_shim32_write64,
|
.write64 = sst_shim32_write64,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user