[alsa-devel] [PATCH 13/13] ASoC: AMD: Manage ACP 2.x SRAM banks power

Alex Deucher alexdeucher at gmail.com
Sat Dec 5 00:40:40 CET 2015


From: Maruthi Srinivas Bayyavarapu <Maruthi.Bayyavarapu at amd.com>

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 at amd.com>
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
---
 sound/soc/amd/acp-pcm-dma.c | 25 +++++++++++---
 sound/soc/amd/acp.c         | 81 ++++++++++++++++++++++++++++++++++++++++++++-
 sound/soc/amd/acp.h         |  3 +-
 3 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 07a26e5..daba64a 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -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.
diff --git a/sound/soc/amd/acp.c b/sound/soc/amd/acp.c
index 0d59be4..ed3f83f 100644
--- a/sound/soc/amd/acp.c
+++ b/sound/soc/amd/acp.c
@@ -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
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
index 53c30ea..a2f3762 100644
--- a/sound/soc/amd/acp.h
+++ b/sound/soc/amd/acp.h
@@ -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 */
-- 
1.8.3.1



More information about the Alsa-devel mailing list