aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJie Yang <yang.jie@intel.com>2014-10-30 10:57:58 -0400
committerMark Brown <broonie@kernel.org>2014-10-30 13:06:21 -0400
commit0d2135ecadb0b2eec5338a7587ba29724ddf612b (patch)
tree27ccb2886e63536fa9852a564d370dbfd8d86eb9
parent35e03a884c41b8fecf77e20de89759deb7c9078a (diff)
ASoC: Intel: Work around to fix HW D3 potential crash issue
When using clock gatings to save power, there are some known issues: 1. core clock gating (DCLCGE) must be disabled during D0 and D3 entry and updating SRAM banks (VDRTCTL0). 2. DSP trunk clock gating (DTCGE) can cause FW crashes, disable it in D0. To align with the new W/A flow from FW team, we must set VDRTCTL0.D3PGD to 1 (D3 power gating disabled) at first startup and keep it all the time. ADSP will be in D0 on first boot by BIOS part of WA. Required delays must be preserved (waiting for HW to stabilize, after enabling CCG, changing SRAM PG, D3PG). D3->D0: 1. Disable core clock gating (VDRTCTL2.DCLCGE = 0) 2. Enable other CG apart from DTCG and DCLCG (VDRTCTL2. DCLCGE and DTCGE = 0) 3. Disable D3PG (VDRTCTL0.D3PGD = 1) 4. Power up necessary SRAM and wait at least for 18 clock cycles for every bank you have powered up 5. Set D0 state(PMCS.PS = 0), wait for HW 6. Restore MCLK (clkctl.smos, disabled in D3 entry point 4) 7. Stall and reset core, set CSR 8. Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us 9. Unreset core 10.Load FW, configure PLL and other necessary things 11.Unstall core Changing SRAM PG during D0: 1. Disable core clock gating (VDRTCTL2.DCLCGE = 0) 2. Set PG mask 3. Wait at least for 18 clock cycles for every bank you have powered up 4. Enable core clock gating, delay 50 us D0->D3: 1. Disable core clock gating (DCLCGE = 0) 2. Stall and reset core 3. Power down entire SRAM and wait at least for 18 clock cycles for every bank (Enable SRAM PG (ISRAMPGE = 0x3FF, DSRAMPGE = 0xFFFFF, D3SRAMPGD = 0), remember about preserving VDRTCTL0.D3PGD = 1) 4. Shutdown PLL, disable MCLK(clkctl.smos = 0), Enable DTCG to save power 5. Set D3 state(PMCS.PS = 3), delay 50 us 6. Enable core clock gating, delay 50 us Signed-off-by: Jie Yang <yang.jie@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/intel/sst-dsp.h14
-rw-r--r--sound/soc/intel/sst-haswell-dsp.c102
2 files changed, 98 insertions, 18 deletions
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h
index 2753b85ac863..f291e32f0077 100644
--- a/sound/soc/intel/sst-dsp.h
+++ b/sound/soc/intel/sst-dsp.h
@@ -159,12 +159,18 @@
159#define SST_VDRTCTL3 0xaC 159#define SST_VDRTCTL3 0xaC
160 160
161/* VDRTCTL0 */ 161/* VDRTCTL0 */
162#define SST_VDRTCL0_APLLSE_MASK 1 162#define SST_VDRTCL0_D3PGD (1 << 0)
163#define SST_VDRTCL0_DSRAMPGE_SHIFT 16 163#define SST_VDRTCL0_D3SRAMPGD (1 << 1)
164#define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT) 164#define SST_VDRTCL0_DSRAMPGE_SHIFT 12
165#define SST_VDRTCL0_ISRAMPGE_SHIFT 6 165#define SST_VDRTCL0_DSRAMPGE_MASK (0xfffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
166#define SST_VDRTCL0_ISRAMPGE_SHIFT 2
166#define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) 167#define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT)
167 168
169/* VDRTCTL2 */
170#define SST_VDRTCL2_DCLCGE (1 << 1)
171#define SST_VDRTCL2_DTCGE (1 << 10)
172#define SST_VDRTCL2_APLLSE_MASK (1 << 31)
173
168/* PMCS */ 174/* PMCS */
169#define SST_PMCS 0x84 175#define SST_PMCS 0x84
170#define SST_PMCS_PS_MASK 0x3 176#define SST_PMCS_PS_MASK 0x3
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c
index 86aea343bfec..57039b00efc2 100644
--- a/sound/soc/intel/sst-haswell-dsp.c
+++ b/sound/soc/intel/sst-haswell-dsp.c
@@ -250,17 +250,42 @@ static irqreturn_t hsw_irq(int irq, void *context)
250static void hsw_set_dsp_D3(struct sst_dsp *sst) 250static void hsw_set_dsp_D3(struct sst_dsp *sst)
251{ 251{
252 u32 val; 252 u32 val;
253 u32 reg;
254
255 /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
256 reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
257 reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
258 writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
253 259
254 /* switch off audio PLL, DRAM & IRAM blocks */ 260 /* enable power gating and switch off DRAM & IRAM blocks */
255 val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); 261 val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
256 val |= SST_VDRTCL0_APLLSE_MASK | SST_VDRTCL0_DSRAMPGE_MASK | 262 val |= SST_VDRTCL0_DSRAMPGE_MASK |
257 SST_VDRTCL0_ISRAMPGE_MASK; 263 SST_VDRTCL0_ISRAMPGE_MASK;
264 val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD);
258 writel(val, sst->addr.pci_cfg + SST_VDRTCTL0); 265 writel(val, sst->addr.pci_cfg + SST_VDRTCTL0);
259 266
260 /* Set D3 state */ 267 /* switch off audio PLL */
268 val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
269 val |= SST_VDRTCL2_APLLSE_MASK;
270 writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
271
272 /* disable MCLK(clkctl.smos = 0) */
273 sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
274 SST_CLKCTL_MASK, 0);
275
276 /* Set D3 state, delay 50 us */
261 val = readl(sst->addr.pci_cfg + SST_PMCS); 277 val = readl(sst->addr.pci_cfg + SST_PMCS);
262 val |= SST_PMCS_PS_MASK; 278 val |= SST_PMCS_PS_MASK;
263 writel(val, sst->addr.pci_cfg + SST_PMCS); 279 writel(val, sst->addr.pci_cfg + SST_PMCS);
280 udelay(50);
281
282 /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
283 reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
284 reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
285 writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
286
287 udelay(50);
288
264} 289}
265 290
266static void hsw_reset(struct sst_dsp *sst) 291static void hsw_reset(struct sst_dsp *sst)
@@ -283,6 +308,16 @@ static int hsw_set_dsp_D0(struct sst_dsp *sst)
283 int tries = 10; 308 int tries = 10;
284 u32 reg; 309 u32 reg;
285 310
311 /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
312 reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
313 reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
314 writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
315
316 /* Disable D3PG (VDRTCTL0.D3PGD = 1) */
317 reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
318 reg |= SST_VDRTCL0_D3PGD;
319 writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
320
286 /* Set D0 state */ 321 /* Set D0 state */
287 reg = readl(sst->addr.pci_cfg + SST_PMCS); 322 reg = readl(sst->addr.pci_cfg + SST_PMCS);
288 reg &= ~SST_PMCS_PS_MASK; 323 reg &= ~SST_PMCS_PS_MASK;
@@ -300,14 +335,6 @@ static int hsw_set_dsp_D0(struct sst_dsp *sst)
300 return -ENODEV; 335 return -ENODEV;
301 336
302finish: 337finish:
303 hsw_reset(sst);
304
305 /* switch on audio PLL, DRAM & IRAM blocks */
306 reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
307 reg &= ~(SST_VDRTCL0_APLLSE_MASK | SST_VDRTCL0_DSRAMPGE_MASK |
308 SST_VDRTCL0_ISRAMPGE_MASK);
309 writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
310
311 /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */ 338 /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
312 sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, 339 sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
313 SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0); 340 SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
@@ -322,6 +349,28 @@ finish:
322 SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0, 349 SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
323 SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0); 350 SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
324 351
352 /* Stall and reset core, set CSR */
353 hsw_reset(sst);
354
355 /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
356 reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
357 reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
358 writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
359
360 udelay(50);
361
362 /* switch on audio PLL */
363 reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
364 reg &= ~SST_VDRTCL2_APLLSE_MASK;
365 writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
366
367 /* set default power gating control, enable power gating control for all blocks. that is,
368 can't be accessed, please enable each block before accessing. */
369 reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
370 reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
371 writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
372
373
325 /* disable DMA finish function for SSP0 & SSP1 */ 374 /* disable DMA finish function for SSP0 & SSP1 */
326 sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1, 375 sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
327 SST_CSR2_SDFD_SSP1); 376 SST_CSR2_SDFD_SSP1);
@@ -343,9 +392,6 @@ finish:
343 sst_dsp_shim_write(sst, 0x80, 0x6); 392 sst_dsp_shim_write(sst, 0x80, 0x6);
344 sst_dsp_shim_write(sst, 0xe0, 0x300a); 393 sst_dsp_shim_write(sst, 0xe0, 0x300a);
345 394
346 /* disable all clock gating */
347 writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2);
348
349 return 0; 395 return 0;
350} 396}
351 397
@@ -497,6 +543,11 @@ static int hsw_block_enable(struct sst_mem_block *block)
497 dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n", 543 dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n",
498 block->type, block->index, block->offset); 544 block->type, block->index, block->offset);
499 545
546 /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
547 val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
548 val &= ~SST_VDRTCL2_DCLCGE;
549 writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
550
500 val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); 551 val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
501 bit = hsw_block_get_bit(block); 552 bit = hsw_block_get_bit(block);
502 writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0); 553 writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0);
@@ -504,6 +555,13 @@ static int hsw_block_enable(struct sst_mem_block *block)
504 /* wait 18 DSP clock ticks */ 555 /* wait 18 DSP clock ticks */
505 udelay(10); 556 udelay(10);
506 557
558 /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
559 val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
560 val |= SST_VDRTCL2_DCLCGE;
561 writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
562
563 udelay(50);
564
507 /*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/ 565 /*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/
508 sst_mem_block_dummy_read(block); 566 sst_mem_block_dummy_read(block);
509 return 0; 567 return 0;
@@ -521,10 +579,26 @@ static int hsw_block_disable(struct sst_mem_block *block)
521 dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n", 579 dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n",
522 block->type, block->index, block->offset); 580 block->type, block->index, block->offset);
523 581
582 /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
583 val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
584 val &= ~SST_VDRTCL2_DCLCGE;
585 writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
586
587
524 val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); 588 val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
525 bit = hsw_block_get_bit(block); 589 bit = hsw_block_get_bit(block);
526 writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); 590 writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
527 591
592 /* wait 18 DSP clock ticks */
593 udelay(10);
594
595 /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
596 val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
597 val |= SST_VDRTCL2_DCLCGE;
598 writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
599
600 udelay(50);
601
528 return 0; 602 return 0;
529} 603}
530 604