diff mbox

[13/13] ASoC: AMD: Manage ACP 2.x SRAM banks power

Message ID 1449272440-8735-13-git-send-email-alexander.deucher@amd.com (mailing list archive)
State New, archived
Headers show

Commit Message

Alex Deucher Dec. 4, 2015, 11:40 p.m. UTC
From: Maruthi Srinivas Bayyavarapu <Maruthi.Bayyavarapu@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@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@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(-)

Comments

Mark Brown Dec. 18, 2015, 12:08 p.m. UTC | #1
On Fri, Dec 04, 2015 at 06:40:40PM -0500, Alex Deucher wrote:

> +void acp_turnonoff_lower_sram_bank(void __iomem *acp_mmio, u16 bank,
> +					bool turnon)

Can we have a name like acp_set_lower_sram_bank_state() or something to
make the boolean a bit more obvious please?  You could probably also
combine this with the equivalent function for the upper bank and select
based on the value which registers to work with, that'd be much clearer
on the user side.

> +	/* 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();

Strange intentation for the continuation lines (usually you'd align with
the '(' for the matching level) and this needs a timeout for safety.
diff mbox

Patch

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 */