Commit 703a6e22 authored by Ravulapati Vishnu vardhan rao's avatar Ravulapati Vishnu vardhan rao Committed by Mark Brown

ASoC: amd: Enabling I2S instance in DMA and DAI

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: default avatarRavulapati Vishnu vardhan rao <Vishnuvardhanrao.Ravulapati@amd.com>
Link: https://lore.kernel.org/r/1577540460-21438-3-git-send-email-Vishnuvardhanrao.Ravulapati@amd.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent c9fe7db6
...@@ -27,10 +27,10 @@ static int acp3x_i2s_set_fmt(struct snd_soc_dai *cpu_dai, ...@@ -27,10 +27,10 @@ static int acp3x_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
switch (mode) { switch (mode) {
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
adata->tdm_mode = false; adata->tdm_mode = TDM_DISABLE;
break; break;
case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_A:
adata->tdm_mode = true; adata->tdm_mode = TDM_ENABLE;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -86,10 +86,22 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream, ...@@ -86,10 +86,22 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{ {
struct i2s_stream_instance *rtd; struct i2s_stream_instance *rtd;
struct snd_soc_pcm_runtime *prtd;
struct snd_soc_card *card;
struct acp3x_platform_info *pinfo;
u32 val; u32 val;
u32 reg_val; u32 reg_val;
prtd = substream->private_data;
rtd = substream->runtime->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 */ /* These values are as per Hardware Spec */
switch (params_format(params)) { switch (params_format(params)) {
...@@ -109,11 +121,25 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream, ...@@ -109,11 +121,25 @@ static int acp3x_i2s_hwparams(struct snd_pcm_substream *substream,
default: default:
return -EINVAL; return -EINVAL;
} }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
reg_val = mmACP_BTTDM_ITER; switch (rtd->i2s_instance) {
else case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_IRER; 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 = rv_readl(rtd->acp3x_base + reg_val);
val = val | (rtd->xfer_resolution << 3); val = val | (rtd->xfer_resolution << 3);
rv_writel(val, rtd->acp3x_base + reg_val); rv_writel(val, rtd->acp3x_base + reg_val);
...@@ -124,10 +150,21 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream, ...@@ -124,10 +150,21 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai) int cmd, struct snd_soc_dai *dai)
{ {
struct i2s_stream_instance *rtd; struct i2s_stream_instance *rtd;
u32 val, period_bytes; struct snd_soc_pcm_runtime *prtd;
int ret, reg_val; 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; 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, period_bytes = frames_to_bytes(substream->runtime,
substream->runtime->period_size); substream->runtime->period_size);
switch (cmd) { switch (cmd) {
...@@ -137,31 +174,75 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream, ...@@ -137,31 +174,75 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
rtd->bytescount = acp_get_byte_count(rtd, rtd->bytescount = acp_get_byte_count(rtd,
substream->stream); substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
reg_val = mmACP_BTTDM_ITER; switch (rtd->i2s_instance) {
rv_writel(period_bytes, rtd->acp3x_base + case I2S_BT_INSTANCE:
mmACP_BT_TX_INTR_WATERMARK_SIZE); 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 { } else {
reg_val = mmACP_BTTDM_IRER; switch (rtd->i2s_instance) {
rv_writel(period_bytes, rtd->acp3x_base + case I2S_BT_INSTANCE:
mmACP_BT_RX_INTR_WATERMARK_SIZE); 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;
}
} }
rv_writel(period_bytes, rtd->acp3x_base + water_val);
val = rv_readl(rtd->acp3x_base + reg_val); val = rv_readl(rtd->acp3x_base + reg_val);
val = val | BIT(0); val = val | BIT(0);
rv_writel(val, rtd->acp3x_base + reg_val); rv_writel(val, rtd->acp3x_base + reg_val);
rv_writel(1, rtd->acp3x_base + mmACP_BTTDM_IER); rv_writel(1, rtd->acp3x_base + ier_val);
ret = 0;
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
reg_val = mmACP_BTTDM_ITER; switch (rtd->i2s_instance) {
else case I2S_BT_INSTANCE:
reg_val = mmACP_BTTDM_IRER; 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 = rv_readl(rtd->acp3x_base + reg_val);
val = val & ~BIT(0); val = val & ~BIT(0);
rv_writel(val, rtd->acp3x_base + reg_val); 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);
ret = 0;
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
......
This diff is collapsed.
...@@ -7,6 +7,11 @@ ...@@ -7,6 +7,11 @@
#include "chip_offset_byte.h" #include "chip_offset_byte.h"
#include <sound/pcm.h> #include <sound/pcm.h>
#define I2S_SP_INSTANCE 0x01
#define I2S_BT_INSTANCE 0x02
#define TDM_ENABLE 1
#define TDM_DISABLE 0
#define ACP3x_DEVS 3 #define ACP3x_DEVS 3
#define ACP3x_PHY_BASE_ADDRESS 0x1240000 #define ACP3x_PHY_BASE_ADDRESS 0x1240000
...@@ -18,8 +23,11 @@ ...@@ -18,8 +23,11 @@
#define ACP3x_BT_TDM_REG_START 0x1242800 #define ACP3x_BT_TDM_REG_START 0x1242800
#define ACP3x_BT_TDM_REG_END 0x1242810 #define ACP3x_BT_TDM_REG_END 0x1242810
#define I2S_MODE 0x04 #define I2S_MODE 0x04
#define I2S_RX_THRESHOLD 27
#define I2S_TX_THRESHOLD 28
#define BT_TX_THRESHOLD 26 #define BT_TX_THRESHOLD 26
#define BT_RX_THRESHOLD 25 #define BT_RX_THRESHOLD 25
#define ACP_ERR_INTR_MASK 29
#define ACP3x_POWER_ON 0x00 #define ACP3x_POWER_ON 0x00
#define ACP3x_POWER_ON_IN_PROGRESS 0x01 #define ACP3x_POWER_ON_IN_PROGRESS 0x01
#define ACP3x_POWER_OFF 0x02 #define ACP3x_POWER_OFF 0x02
...@@ -27,19 +35,28 @@ ...@@ -27,19 +35,28 @@
#define ACP3x_SOFT_RESET__SoftResetAudDone_MASK 0x00010001 #define ACP3x_SOFT_RESET__SoftResetAudDone_MASK 0x00010001
#define ACP_SRAM_PTE_OFFSET 0x02050000 #define ACP_SRAM_PTE_OFFSET 0x02050000
#define ACP_SRAM_SP_PB_PTE_OFFSET 0x0
#define ACP_SRAM_SP_CP_PTE_OFFSET 0x100
#define ACP_SRAM_BT_PB_PTE_OFFSET 0x200
#define ACP_SRAM_BT_CP_PTE_OFFSET 0x300
#define PAGE_SIZE_4K_ENABLE 0x2 #define PAGE_SIZE_4K_ENABLE 0x2
#define MEM_WINDOW_START 0x4000000 #define I2S_SP_TX_MEM_WINDOW_START 0x4000000
#define PLAYBACK_FIFO_ADDR_OFFSET 0x400 #define I2S_SP_RX_MEM_WINDOW_START 0x4020000
#define CAPTURE_FIFO_ADDR_OFFSET 0x500 #define I2S_BT_TX_MEM_WINDOW_START 0x4040000
#define I2S_BT_RX_MEM_WINDOW_START 0x4060000
#define SP_PB_FIFO_ADDR_OFFSET 0x500
#define SP_CAPT_FIFO_ADDR_OFFSET 0x700
#define BT_PB_FIFO_ADDR_OFFSET 0x900
#define BT_CAPT_FIFO_ADDR_OFFSET 0xB00
#define PLAYBACK_MIN_NUM_PERIODS 2 #define PLAYBACK_MIN_NUM_PERIODS 2
#define PLAYBACK_MAX_NUM_PERIODS 8 #define PLAYBACK_MAX_NUM_PERIODS 8
#define PLAYBACK_MAX_PERIOD_SIZE 16384 #define PLAYBACK_MAX_PERIOD_SIZE 8192
#define PLAYBACK_MIN_PERIOD_SIZE 4096 #define PLAYBACK_MIN_PERIOD_SIZE 1024
#define CAPTURE_MIN_NUM_PERIODS 2 #define CAPTURE_MIN_NUM_PERIODS 2
#define CAPTURE_MAX_NUM_PERIODS 8 #define CAPTURE_MAX_NUM_PERIODS 8
#define CAPTURE_MAX_PERIOD_SIZE 16384 #define CAPTURE_MAX_PERIOD_SIZE 8192
#define CAPTURE_MIN_PERIOD_SIZE 4096 #define CAPTURE_MIN_PERIOD_SIZE 1024
#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS) #define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
#define MIN_BUFFER MAX_BUFFER #define MIN_BUFFER MAX_BUFFER
...@@ -66,14 +83,20 @@ struct i2s_dev_data { ...@@ -66,14 +83,20 @@ struct i2s_dev_data {
void __iomem *acp3x_base; void __iomem *acp3x_base;
struct snd_pcm_substream *play_stream; struct snd_pcm_substream *play_stream;
struct snd_pcm_substream *capture_stream; struct snd_pcm_substream *capture_stream;
struct snd_pcm_substream *i2ssp_play_stream;
struct snd_pcm_substream *i2ssp_capture_stream;
}; };
struct i2s_stream_instance { struct i2s_stream_instance {
u16 num_pages; u16 num_pages;
u16 i2s_instance;
u16 capture_channel;
u16 direction;
u16 channels; u16 channels;
u32 xfer_resolution; u32 xfer_resolution;
u64 bytescount; u32 val;
dma_addr_t dma_addr; dma_addr_t dma_addr;
u64 bytescount;
void __iomem *acp3x_base; void __iomem *acp3x_base;
}; };
...@@ -93,15 +116,36 @@ static inline u64 acp_get_byte_count(struct i2s_stream_instance *rtd, ...@@ -93,15 +116,36 @@ static inline u64 acp_get_byte_count(struct i2s_stream_instance *rtd,
u64 byte_count; u64 byte_count;
if (direction == SNDRV_PCM_STREAM_PLAYBACK) { if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
byte_count = rv_readl(rtd->acp3x_base + switch (rtd->i2s_instance) {
mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH); case I2S_BT_INSTANCE:
byte_count |= rv_readl(rtd->acp3x_base + byte_count = rv_readl(rtd->acp3x_base +
mmACP_BT_TX_LINEARPOSITIONCNTR_LOW); mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH);
byte_count |= rv_readl(rtd->acp3x_base +
mmACP_BT_TX_LINEARPOSITIONCNTR_LOW);
break;
case I2S_SP_INSTANCE:
default:
byte_count = rv_readl(rtd->acp3x_base +
mmACP_I2S_TX_LINEARPOSITIONCNTR_HIGH);
byte_count |= rv_readl(rtd->acp3x_base +
mmACP_I2S_TX_LINEARPOSITIONCNTR_LOW);
}
} else { } else {
byte_count = rv_readl(rtd->acp3x_base + switch (rtd->i2s_instance) {
mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH); case I2S_BT_INSTANCE:
byte_count |= rv_readl(rtd->acp3x_base + byte_count = rv_readl(rtd->acp3x_base +
mmACP_BT_RX_LINEARPOSITIONCNTR_LOW); mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH);
byte_count |= rv_readl(rtd->acp3x_base +
mmACP_BT_RX_LINEARPOSITIONCNTR_LOW);
break;
case I2S_SP_INSTANCE:
default:
byte_count = rv_readl(rtd->acp3x_base +
mmACP_I2S_RX_LINEARPOSITIONCNTR_HIGH);
byte_count |= rv_readl(rtd->acp3x_base +
mmACP_I2S_RX_LINEARPOSITIONCNTR_LOW);
}
} }
return byte_count; return byte_count;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment