ASoC: AMD: Manage ACP 2.x SRAM banks power
authorMaruthi Srinivas Bayyavarapu <Maruthi.Bayyavarapu@amd.com>
Fri, 8 Jan 2016 23:22:11 +0000 (18:22 -0500)
committerMark Brown <broonie@kernel.org>
Sun, 10 Jan 2016 12:44:13 +0000 (12:44 +0000)
ACP SRAM banks gets turned on when ACP is powered on.
Not all banks are used for playback/capture. So, power on
required banks during audio device open and power off during
audio device close.

Signed-off-by: Maruthi Bayyavarapu <maruthi.bayyavarapu@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/amd/acp-pcm-dma.c

index c0819b5..cc8b841 100644 (file)
@@ -376,9 +376,57 @@ static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num)
        return 0;
 }
 
+static void acp_set_sram_bank_state(void __iomem *acp_mmio, u16 bank,
+                                       bool power_on)
+{
+       u32 val, req_reg, sts_reg, sts_reg_mask;
+       u32 loops = 1000;
+
+       if (bank < 32) {
+               req_reg = mmACP_MEM_SHUT_DOWN_REQ_LO;
+               sts_reg = mmACP_MEM_SHUT_DOWN_STS_LO;
+               sts_reg_mask = 0xFFFFFFFF;
+
+       } else {
+               bank -= 32;
+               req_reg = mmACP_MEM_SHUT_DOWN_REQ_HI;
+               sts_reg = mmACP_MEM_SHUT_DOWN_STS_HI;
+               sts_reg_mask = 0x0000FFFF;
+       }
+
+       val = acp_reg_read(acp_mmio, req_reg);
+       if (val & (1 << bank)) {
+               /* bank is in off state */
+               if (power_on == true)
+                       /* request to on */
+                       val &= ~(1 << bank);
+               else
+                       /* request to off */
+                       return;
+       } else {
+               /* bank is in on state */
+               if (power_on == false)
+                       /* request to off */
+                       val |= 1 << bank;
+               else
+                       /* request to on */
+                       return;
+       }
+       acp_reg_write(val, acp_mmio, req_reg);
+
+       while (acp_reg_read(acp_mmio, sts_reg) != sts_reg_mask) {
+               if (!loops--) {
+                       pr_err("ACP SRAM bank %d state change failed\n", bank);
+                       break;
+               }
+               cpu_relax();
+       }
+}
+
 /* Initialize and bring ACP hardware to default state. */
 static int acp_init(void __iomem *acp_mmio)
 {
+       u16 bank;
        u32 val, count, sram_pte_offset;
 
        /* Assert Soft reset of ACP */
@@ -447,6 +495,13 @@ static 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 < 48; bank++)
+               acp_set_sram_bank_state(acp_mmio, bank, false);
+
        return 0;
 }
 
@@ -559,6 +614,7 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
 
 static int acp_dma_open(struct snd_pcm_substream *substream)
 {
+       u16 bank;
        int ret = 0;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *prtd = substream->private_data;
@@ -592,10 +648,17 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
        if (!intr_data->play_stream && !intr_data->capture_stream)
                acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
 
-       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_set_sram_bank_state(intr_data->acp_mmio, bank,
+                                               true);
+       } else {
                intr_data->capture_stream = substream;
+               for (bank = 5; bank <= 8; bank++)
+                       acp_set_sram_bank_state(intr_data->acp_mmio, bank,
+                                               true);
+       }
 
        return 0;
 }
@@ -627,6 +690,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
        pg = virt_to_page(substream->dma_buffer.area);
 
        if (pg != NULL) {
+               acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
                /* Save for runtime private data */
                rtd->pg = pg;
                rtd->order = get_order(size);
@@ -802,6 +866,7 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
 
 static int acp_dma_close(struct snd_pcm_substream *substream)
 {
+       u16 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;
@@ -809,10 +874,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_set_sram_bank_state(adata->acp_mmio, bank,
+                                               false);
+       } else {
                adata->capture_stream = NULL;
+               for (bank = 5; bank <= 8; bank++)
+                       acp_set_sram_bank_state(adata->acp_mmio, bank,
+                                               false);
+       }
 
        /* Disable ACP irq, when the current stream is being closed and
         * another stream is also not active.
@@ -906,17 +978,25 @@ static int acp_audio_remove(struct platform_device *pdev)
 
 static int acp_pcm_resume(struct device *dev)
 {
+       u16 bank;
        struct audio_drv_data *adata = dev_get_drvdata(dev);
 
        acp_init(adata->acp_mmio);
 
-       if (adata->play_stream && adata->play_stream->runtime)
+       if (adata->play_stream && adata->play_stream->runtime) {
+               for (bank = 1; bank <= 4; bank++)
+                       acp_set_sram_bank_state(adata->acp_mmio, bank,
+                                               true);
                config_acp_dma(adata->acp_mmio,
                                adata->play_stream->runtime->private_data);
-       if (adata->capture_stream && adata->capture_stream->runtime)
+       }
+       if (adata->capture_stream && adata->capture_stream->runtime) {
+               for (bank = 5; bank <= 8; bank++)
+                       acp_set_sram_bank_state(adata->acp_mmio, bank,
+                                               true);
                config_acp_dma(adata->acp_mmio,
                                adata->capture_stream->runtime->private_data);
-
+       }
        acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
        return 0;
 }