@@ -133,6 +133,7 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
static int acp_dma_open(struct snd_pcm_substream *substream)
{
+ u32 bank;
int ret = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *prtd = substream->private_data;
@@ -166,10 +167,17 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
if (!intr_data->play_stream && !intr_data->capture_stream)
acp_enable_external_interrupts(adata->acp_mmio, 1);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
intr_data->play_stream = substream;
- else
+ for (bank = 1; bank <= 4; bank++)
+ acp_turnonoff_lower_sram_bank(intr_data->acp_mmio, bank,
+ true);
+ } else {
intr_data->capture_stream = substream;
+ for (bank = 5; bank <= 8; bank++)
+ acp_turnonoff_lower_sram_bank(intr_data->acp_mmio, bank,
+ true);
+ }
return 0;
}
@@ -201,6 +209,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
pg = virt_to_page(substream->dma_buffer.area);
if (pg != NULL) {
+ acp_turnonoff_lower_sram_bank(rtd->acp_mmio, 0, true);
/* Save for runtime private data */
rtd->pg = pg;
rtd->order = get_order(size);
@@ -364,6 +373,7 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
static int acp_dma_close(struct snd_pcm_substream *substream)
{
+ u32 bank;
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_substream_data *rtd = runtime->private_data;
struct snd_soc_pcm_runtime *prtd = substream->private_data;
@@ -371,10 +381,17 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
kfree(rtd);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
adata->play_stream = NULL;
- else
+ for (bank = 1; bank <= 4; bank++)
+ acp_turnonoff_lower_sram_bank(adata->acp_mmio, bank,
+ false);
+ } else {
adata->capture_stream = NULL;
+ for (bank = 5; bank <= 8; bank++)
+ acp_turnonoff_lower_sram_bank(adata->acp_mmio, bank,
+ false);
+ }
/* Disable ACP irq, when the current stream is being closed and
* another stream is also not active.
@@ -462,10 +462,79 @@ int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num)
return 0;
}
+void acp_turnonoff_lower_sram_bank(void __iomem *acp_mmio, u16 bank,
+ bool turnon)
+{
+ u32 val;
+
+ val = acp_reg_read(acp_mmio, mmACP_MEM_SHUT_DOWN_REQ_LO);
+ if (val & (1 << bank)) {
+ /* bank is in off state */
+ if (turnon == true)
+ /* request to on */
+ val &= ~(1 << bank);
+ else
+ /* request to off */
+ return;
+ } else {
+ /* bank is in on state */
+ if (turnon == false)
+ /* request to off */
+ val |= 1 << bank;
+ else
+ /* request to on */
+ return;
+ }
+ acp_reg_write(val, acp_mmio,
+ mmACP_MEM_SHUT_DOWN_REQ_LO);
+ /* If ACP_MEM_SHUT_DOWN_STS_LO is 0xFFFFFFFF, then
+ * shutdown sequence is complete.
+ */
+ while (acp_reg_read(acp_mmio,
+ mmACP_MEM_SHUT_DOWN_STS_LO)
+ != 0xFFFFFFFF)
+ cpu_relax();
+}
+
+void acp_turnonoff_higher_sram_bank(void __iomem *acp_mmio, u16 bank,
+ bool turnon)
+{
+ u32 val;
+
+ bank -= 32;
+ val = acp_reg_read(acp_mmio, mmACP_MEM_SHUT_DOWN_REQ_HI);
+ if (val & (1 << bank)) {
+ /* bank is in off state */
+ if (turnon == true)
+ /* request to on */
+ val &= ~(1 << bank);
+ else
+ /* request to off */
+ return;
+ } else {
+ /* bank is in on state */
+ if (turnon == false)
+ /* request to off */
+ val |= 1 << bank;
+ else
+ /* request to on */
+ return;
+ }
+ acp_reg_write(val, acp_mmio,
+ mmACP_MEM_SHUT_DOWN_REQ_HI);
+ /* If ACP_MEM_SHUT_DOWN_STS_LO is 0xFFFFFFFF, then
+ * shutdown sequence is complete.
+ */
+ while (acp_reg_read(acp_mmio,
+ mmACP_MEM_SHUT_DOWN_STS_HI)
+ != 0x0000FFFF)
+ cpu_relax();
+}
+
/* Initialize and bring ACP hardware to default state. */
int acp_init(void __iomem *acp_mmio)
{
- u32 val;
+ u32 val, bank;
u32 count;
/* Assert Soft reset of ACP */
@@ -527,6 +596,16 @@ int acp_init(void __iomem *acp_mmio)
acp_reg_write(ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK,
acp_mmio, mmACP_EXTERNAL_INTR_CNTL);
+ /* When ACP_TILE_P1 is turned on, all SRAM banks get turned on.
+ * Now, turn off all of them. This can't be done in 'poweron' of
+ * ACP pm domain, as this requires ACP to be initialized.
+ */
+ for (bank = 1; bank < 32; bank++)
+ acp_turnonoff_lower_sram_bank(acp_mmio, bank, false);
+
+ for (bank = 32; bank < 48; bank++)
+ acp_turnonoff_higher_sram_bank(acp_mmio, bank, false);
+
/* Designware I2S driver requries proper capabilities
* from mmACP_I2SMICSP_COMP_PARAM_1 register. The register
* reports playback and capture capabilities though the
@@ -135,5 +135,6 @@ extern void acp_enable_external_interrupts(void __iomem *acp_mmio,
extern u32 acp_get_intr_flag(void __iomem *acp_mmio);
extern u16 get_dscr_idx(void __iomem *acp_mmio, int direction);
extern void acp_ext_stat_clear_dmaioc(void __iomem *acp_mmio, u8 ch_num);
-
+extern void acp_turnonoff_lower_sram_bank(void __iomem *acp_mmio, u16 bank,
+ bool turnon);
#endif /*__ACP_HW_H */