On 11/22/2019 3:14 PM, Ravulapati Vishnu vardhan rao wrote:
This patch adds I2S SP support in ACP PCM DMA and DAI. Added I2S support in DMA and DAI probe,its hw_params handling its open and close functionalities. This enables to open and close on the SP instance for playback and capture.
Signed-off-by: Ravulapati Vishnu vardhan rao Vishnuvardhanrao.Ravulapati@amd.com
sound/soc/amd/raven/acp3x-i2s.c | 123 +++++++++++++++++---- sound/soc/amd/raven/acp3x-pcm-dma.c | 214 ++++++++++++++++++++++++------------ sound/soc/amd/raven/acp3x.h | 77 ++++++++++--- 3 files changed, 309 insertions(+), 105 deletions(-)
diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c index cdc1c61..7f05782 100644 --- a/sound/soc/amd/raven/acp3x-i2s.c +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -28,10 +28,10 @@ static int acp3x_i2s_set_fmt(struct snd_soc_dai *cpu_dai, mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; switch (mode) { case SND_SOC_DAIFMT_I2S:
adata->tdm_mode = false;
break; case SND_SOC_DAIFMT_DSP_A:adata->tdm_mode = TDM_DISABLE;
adata->tdm_mode = true;
break; default: return -EINVAL;adata->tdm_mode = TDM_ENABLE;
@@ -87,10 +87,22 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct i2s_stream_instance *rtd;
struct snd_soc_pcm_runtime *prtd;
struct snd_soc_card *card;
struct acp3x_platform_info *pinfo; u32 val; u32 reg_val;
prtd = substream->private_data; rtd = substream->runtime->private_data;
card = prtd->card;
pinfo = snd_soc_card_get_drvdata(card);
if (pinfo) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
rtd->i2s_instance = pinfo->play_i2s_instance;
else
rtd->i2s_instance = pinfo->cap_i2s_instance;
}
/* These values are as per Hardware Spec */ switch (params_format(params)) {
@@ -110,11 +122,25 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream, default: return -EINVAL; }
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
reg_val = mmACP_BTTDM_ITER;
- else
reg_val = mmACP_BTTDM_IRER;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_ITER;
break;
case I2S_SP_INSTANCE:
default:
reg_val = mmACP_I2STDM_ITER;
}
- } else {
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_IRER;
break;
case I2S_SP_INSTANCE:
default:
reg_val = mmACP_I2STDM_IRER;
}
- } val = rv_readl(rtd->acp3x_base + reg_val); val = val | (rtd->xfer_resolution << 3); rv_writel(val, rtd->acp3x_base + reg_val);
@@ -125,10 +151,21 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct i2s_stream_instance *rtd;
- u32 val, period_bytes;
- int ret, reg_val;
struct snd_soc_pcm_runtime *prtd;
struct snd_soc_card *card;
struct acp3x_platform_info *pinfo;
u32 ret, val, period_bytes, reg_val, ier_val, water_val;
prtd = substream->private_data; rtd = substream->runtime->private_data;
card = prtd->card;
pinfo = snd_soc_card_get_drvdata(card);
if (pinfo) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
rtd->i2s_instance = pinfo->play_i2s_instance;
else
rtd->i2s_instance = pinfo->cap_i2s_instance;
} period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size); switch (cmd) {
@@ -138,31 +175,75 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream, rtd->bytescount = acp_get_byte_count(rtd, substream->stream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
reg_val = mmACP_BTTDM_ITER;
rv_writel(period_bytes, rtd->acp3x_base +
mmACP_BT_TX_INTR_WATERMARK_SIZE);
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
water_val =
mmACP_BT_TX_INTR_WATERMARK_SIZE;
reg_val = mmACP_BTTDM_ITER;
ier_val = mmACP_BTTDM_IER;
break;
case I2S_SP_INSTANCE:
default:
water_val =
mmACP_I2S_TX_INTR_WATERMARK_SIZE;
reg_val = mmACP_I2STDM_ITER;
ier_val = mmACP_I2STDM_IER;
} else {}
reg_val = mmACP_BTTDM_IRER;
rv_writel(period_bytes, rtd->acp3x_base +
mmACP_BT_RX_INTR_WATERMARK_SIZE);
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
water_val =
mmACP_BT_RX_INTR_WATERMARK_SIZE;
reg_val = mmACP_BTTDM_IRER;
ier_val = mmACP_BTTDM_IER;
break;
case I2S_SP_INSTANCE:
default:
water_val =
mmACP_I2S_RX_INTR_WATERMARK_SIZE;
reg_val = mmACP_I2STDM_IRER;
ier_val = mmACP_I2STDM_IER;
}}
val = rv_readl(rtd->acp3x_base + reg_val); val = val | BIT(0); rv_writel(val, rtd->acp3x_base + reg_val);rv_writel(period_bytes, rtd->acp3x_base + water_val);
rv_writel(1, rtd->acp3x_base + mmACP_BTTDM_IER);
rv_writel(1, rtd->acp3x_base + ier_val);
break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:ret = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
reg_val = mmACP_BTTDM_ITER;
else
reg_val = mmACP_BTTDM_IRER;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_ITER;
ier_val = mmACP_BTTDM_IER;
break;
case I2S_SP_INSTANCE:
default:
reg_val = mmACP_I2STDM_ITER;
ier_val = mmACP_I2STDM_IER;
}
} else {
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_IRER;
ier_val = mmACP_BTTDM_IER;
break;
case I2S_SP_INSTANCE:
default:
reg_val = mmACP_I2STDM_IRER;
ier_val = mmACP_I2STDM_IER;
}
}
val = rv_readl(rtd->acp3x_base + reg_val); val = val & ~BIT(0); rv_writel(val, rtd->acp3x_base + reg_val);
rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER);
rv_writel(0, rtd->acp3x_base + ier_val);
break; default: ret = -EINVAL;ret = 0;
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index f8ad7ce..77f2ed5 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -194,15 +194,31 @@ static irqreturn_t i2s_irq_handler(int irq, void *dev_id) static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction) { u16 page_idx;
- u32 low, high, val, acp_fifo_addr;
- dma_addr_t addr = rtd->dma_addr;
- u32 low, high, val, acp_fifo_addr, reg_fifo_addr;
- u32 reg_ringbuf_size, reg_dma_size, reg_fifo_size;
- dma_addr_t addr;
- /* 8 scratch registers used to map one 64 bit address */
- if (direction == SNDRV_PCM_STREAM_PLAYBACK)
val = 0;
- else
val = rtd->num_pages * 8;
addr = rtd->dma_addr;
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
val = ACP_SRAM_BT_PB_PTE_OFFSET;
break;
case I2S_SP_INSTANCE:
default:
val = ACP_SRAM_SP_PB_PTE_OFFSET;
}
} else {
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
val = ACP_SRAM_BT_CP_PTE_OFFSET;
break;
case I2S_SP_INSTANCE:
default:
val = ACP_SRAM_SP_CP_PTE_OFFSET;
}
} /* Group Enable */ rv_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp3x_base + mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
@@ -224,38 +240,61 @@ static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction) }
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
/* Config ringbuffer */
rv_writel(MEM_WINDOW_START, rtd->acp3x_base +
mmACP_BT_TX_RINGBUFADDR);
rv_writel(MAX_BUFFER, rtd->acp3x_base +
mmACP_BT_TX_RINGBUFSIZE);
rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_TX_DMA_SIZE);
/* Config audio fifo */
acp_fifo_addr = ACP_SRAM_PTE_OFFSET + (rtd->num_pages * 8)
+ PLAYBACK_FIFO_ADDR_OFFSET;
rv_writel(acp_fifo_addr, rtd->acp3x_base +
mmACP_BT_TX_FIFOADDR);
rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_TX_FIFOSIZE);
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
reg_ringbuf_size = mmACP_BT_TX_RINGBUFSIZE;
reg_dma_size = mmACP_BT_TX_DMA_SIZE;
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
BT_PB_FIFO_ADDR_OFFSET;
reg_fifo_addr = mmACP_BT_TX_FIFOADDR;
reg_fifo_size = mmACP_BT_TX_FIFOSIZE;
rv_writel(I2S_BT_TX_MEM_WINDOW_START,
rtd->acp3x_base + mmACP_BT_TX_RINGBUFADDR);
break;
case I2S_SP_INSTANCE:
default:
reg_ringbuf_size = mmACP_I2S_TX_RINGBUFSIZE;
reg_dma_size = mmACP_I2S_TX_DMA_SIZE;
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
SP_PB_FIFO_ADDR_OFFSET;
reg_fifo_addr = mmACP_I2S_TX_FIFOADDR;
reg_fifo_size = mmACP_I2S_TX_FIFOSIZE;
rv_writel(I2S_SP_TX_MEM_WINDOW_START,
rtd->acp3x_base + mmACP_I2S_TX_RINGBUFADDR);
} else {}
/* Config ringbuffer */
rv_writel(MEM_WINDOW_START + MAX_BUFFER, rtd->acp3x_base +
mmACP_BT_RX_RINGBUFADDR);
rv_writel(MAX_BUFFER, rtd->acp3x_base +
mmACP_BT_RX_RINGBUFSIZE);
rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_RX_DMA_SIZE);
/* Config audio fifo */
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
(rtd->num_pages * 8) + CAPTURE_FIFO_ADDR_OFFSET;
rv_writel(acp_fifo_addr, rtd->acp3x_base +
mmACP_BT_RX_FIFOADDR);
rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_RX_FIFOSIZE);
- }
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
reg_ringbuf_size = mmACP_BT_RX_RINGBUFSIZE;
reg_dma_size = mmACP_BT_RX_DMA_SIZE;
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
BT_CAPT_FIFO_ADDR_OFFSET;
reg_fifo_addr = mmACP_BT_RX_FIFOADDR;
reg_fifo_size = mmACP_BT_RX_FIFOSIZE;
rv_writel(I2S_BT_RX_MEM_WINDOW_START,
rtd->acp3x_base + mmACP_BT_RX_RINGBUFADDR);
break;
- /* Enable watermark/period interrupt to host */
- rv_writel(BIT(BT_TX_THRESHOLD) | BIT(BT_RX_THRESHOLD),
rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
case I2S_SP_INSTANCE:
default:
reg_ringbuf_size = mmACP_I2S_RX_RINGBUFSIZE;
reg_dma_size = mmACP_I2S_RX_DMA_SIZE;
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
SP_CAPT_FIFO_ADDR_OFFSET;
reg_fifo_addr = mmACP_I2S_RX_FIFOADDR;
reg_fifo_size = mmACP_I2S_RX_FIFOSIZE;
rv_writel(I2S_SP_RX_MEM_WINDOW_START,
rtd->acp3x_base + mmACP_I2S_RX_RINGBUFADDR);
}
}
rv_writel(MAX_BUFFER, rtd->acp3x_base + reg_ringbuf_size);
rv_writel(DMA_SIZE, rtd->acp3x_base + reg_dma_size);
rv_writel(acp_fifo_addr, rtd->acp3x_base + reg_fifo_addr);
rv_writel(FIFO_SIZE, rtd->acp3x_base + reg_fifo_size);
rv_writel(BIT(I2S_RX_THRESHOLD) | BIT(BT_RX_THRESHOLD)
| BIT(I2S_TX_THRESHOLD) | BIT(BT_TX_THRESHOLD),
rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
}
static int acp3x_dma_open(struct snd_soc_component *component,
@@ -288,17 +327,21 @@ static int acp3x_dma_open(struct snd_soc_component *component, return ret; }
- if (!adata->play_stream && !adata->capture_stream)
- if (!adata->play_stream && !adata->capture_stream &&
rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);adata->i2ssp_play_stream && !adata->i2ssp_capture_stream)
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { adata->play_stream = substream;
- else
adata->i2ssp_play_stream = substream;
} else { adata->capture_stream = substream;
adata->i2ssp_capture_stream = substream;
}
i2s_data->acp3x_base = adata->acp3x_base; runtime->private_data = i2s_data;
- return 0;
- return ret; }
@@ -306,16 +349,28 @@ static int acp3x_dma_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) {
- struct snd_pcm_runtime *runtime; struct i2s_stream_instance *rtd;
- struct snd_soc_pcm_runtime *prtd;
- struct snd_soc_card *card;
- struct acp3x_platform_info *pinfo; int status; u64 size;
- runtime = substream->runtime;
- rtd = substream->private_data;
prtd = substream->private_data;
card = prtd->card;
pinfo = snd_soc_card_get_drvdata(card);
rtd = substream->runtime->private_data; if (!rtd) return -EINVAL;
if (pinfo)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
rtd->i2s_instance = pinfo->play_i2s_instance;
else
rtd->i2s_instance = pinfo->cap_i2s_instance;
else
pr_err("pinfo failed\n");
size = params_buffer_bytes(params); status = snd_pcm_lib_malloc_pages(substream, size); if (status < 0)
@@ -336,12 +391,25 @@ static int acp3x_dma_hw_params(struct snd_soc_component *component, static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) {
struct snd_soc_pcm_runtime *prtd;
struct snd_soc_card *card;
struct acp3x_platform_info *pinfo; struct i2s_stream_instance *rtd; u32 pos; u32 buffersize; u64 bytescount;
prtd = substream->private_data;
card = prtd->card; rtd = substream->runtime->private_data;
pinfo = snd_soc_card_get_drvdata(card);
if (pinfo) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
rtd->i2s_instance = pinfo->play_i2s_instance;
else
rtd->i2s_instance = pinfo->cap_i2s_instance;
}
buffersize = frames_to_bytes(substream->runtime, substream->runtime->buffer_size); bytescount = acp_get_byte_count(rtd, substream->stream);
@@ -386,15 +454,19 @@ static int acp3x_dma_close(struct snd_soc_component *component, component = snd_soc_rtdcom_lookup(prtd, DRV_NAME); adata = dev_get_drvdata(component->dev);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { adata->play_stream = NULL;
- else
adata->i2ssp_play_stream = NULL;
} else { adata->capture_stream = NULL;
adata->i2ssp_capture_stream = NULL;
}
/* Disable ACP irq, when the current stream is being closed and
- another stream is also not active.
*/
- if (!adata->play_stream && !adata->capture_stream)
- if (!adata->play_stream && !adata->capture_stream &&
rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); return 0; }!adata->i2ssp_play_stream && !adata->i2ssp_capture_stream)
@@ -503,7 +575,7 @@ static int acp3x_resume(struct device *dev) { struct i2s_dev_data *adata; int status;
- u32 val;
u32 val, reg_val, frmt_val;
adata = dev_get_drvdata(dev); status = acp3x_init(adata->acp3x_base);
@@ -514,32 +586,38 @@ static int acp3x_resume(struct device *dev) struct i2s_stream_instance *rtd = adata->play_stream->runtime->private_data; config_acp3x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK);
rv_writel((rtd->xfer_resolution << 3),
rtd->acp3x_base + mmACP_BTTDM_ITER);
if (adata->tdm_mode == true) {
rv_writel(adata->tdm_fmt, adata->acp3x_base +
mmACP_BTTDM_TXFRMT);
val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
rv_writel((val | 0x2), adata->acp3x_base +
mmACP_BTTDM_ITER);
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_ITER;
frmt_val = mmACP_BTTDM_TXFRMT;
break;
case I2S_SP_INSTANCE:
default:
reg_val = mmACP_I2STDM_ITER;
} }frmt_val = mmACP_I2STDM_TXFRMT;
- if (adata->capture_stream && adata->capture_stream->runtime) { struct i2s_stream_instance *rtd = adata->capture_stream->runtime->private_data; config_acp3x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
rv_writel((rtd->xfer_resolution << 3),
rtd->acp3x_base + mmACP_BTTDM_IRER);
if (adata->tdm_mode == true) {
rv_writel(adata->tdm_fmt, adata->acp3x_base +
mmACP_BTTDM_RXFRMT);
val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
rv_writel((val | 0x2), adata->acp3x_base +
mmACP_BTTDM_IRER);
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_IRER;
frmt_val = mmACP_BTTDM_RXFRMT;
break;
case I2S_SP_INSTANCE:
default:
reg_val = mmACP_I2STDM_IRER;
} }frmt_val = mmACP_I2STDM_RXFRMT;
- rv_writel((rtd->xfer_resolution << 3), rtd->acp3x_base + reg_val);
Build error, rtd is declared in scope of 'if' condition. Move the deceleration to function.
Thanks,
Akshu