Skip to content

Commit

Permalink
Add i2s/tdm support for acp7.0 and acp7.1 platforms
Browse files Browse the repository at this point in the history
Merge series from Venkata Prasad Potturu <[email protected]>:

1. Refactor acp generic driver to support all platforms.
2. Add i2s/tdm and support for acp7.0  and acp7.1 platforms.
  • Loading branch information
broonie committed Sep 3, 2024
2 parents 56f97d4 + 3f60059 commit 1324e5f
Show file tree
Hide file tree
Showing 7 changed files with 387 additions and 138 deletions.
188 changes: 145 additions & 43 deletions sound/soc/amd/acp/acp-i2s.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id)

switch (chip->acp_rev) {
case ACP63_DEV:
case ACP70_DEV:
case ACP71_DEV:
val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, adata->lrclk_div);
val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, adata->bclk_div);
break;
Expand Down Expand Up @@ -95,9 +97,11 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
{
struct device *dev = dai->component->dev;
struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai);
struct acp_chip_info *chip;
struct acp_stream *stream;
int slot_len, no_of_slots;

chip = dev_get_platdata(dev);
switch (slot_width) {
case SLOT_WIDTH_8:
slot_len = 8;
Expand All @@ -116,28 +120,69 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
return -EINVAL;
}

switch (slots) {
case 1 ... 7:
no_of_slots = slots;
switch (chip->acp_rev) {
case ACP3X_DEV:
case ACP6X_DEV:
switch (slots) {
case 1 ... 7:
no_of_slots = slots;
break;
case 8:
no_of_slots = 0;
break;
default:
dev_err(dev, "Unsupported slots %d\n", slots);
return -EINVAL;
}
break;
case 8:
no_of_slots = 0;
case ACP63_DEV:
case ACP70_DEV:
case ACP71_DEV:
switch (slots) {
case 1 ... 31:
no_of_slots = slots;
break;
case 32:
no_of_slots = 0;
break;
default:
dev_err(dev, "Unsupported slots %d\n", slots);
return -EINVAL;
}
break;
default:
dev_err(dev, "Unsupported slots %d\n", slots);
dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev);
return -EINVAL;
}

slots = no_of_slots;

spin_lock_irq(&adata->acp_lock);
list_for_each_entry(stream, &adata->stream_list, list) {
if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
adata->tdm_tx_fmt[stream->dai_id - 1] =
switch (chip->acp_rev) {
case ACP3X_DEV:
case ACP6X_DEV:
if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
adata->tdm_tx_fmt[stream->dai_id - 1] =
FRM_LEN | (slots << 15) | (slot_len << 18);
else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
adata->tdm_rx_fmt[stream->dai_id - 1] =
else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
adata->tdm_rx_fmt[stream->dai_id - 1] =
FRM_LEN | (slots << 15) | (slot_len << 18);
break;
case ACP63_DEV:
case ACP70_DEV:
case ACP71_DEV:
if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
adata->tdm_tx_fmt[stream->dai_id - 1] =
FRM_LEN | (slots << 13) | (slot_len << 18);
else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
adata->tdm_rx_fmt[stream->dai_id - 1] =
FRM_LEN | (slots << 13) | (slot_len << 18);
break;
default:
dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev);
return -EINVAL;
}
}
spin_unlock_irq(&adata->acp_lock);
return 0;
Expand Down Expand Up @@ -296,6 +341,41 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
default:
return -EINVAL;
}

switch (params_rate(params)) {
case 8000:
case 16000:
case 24000:
case 48000:
case 96000:
case 192000:
switch (params_channels(params)) {
case 2:
break;
case 4:
bclk_div_val = bclk_div_val >> 1;
lrclk_div_val = lrclk_div_val << 1;
break;
case 8:
bclk_div_val = bclk_div_val >> 2;
lrclk_div_val = lrclk_div_val << 2;
break;
case 16:
bclk_div_val = bclk_div_val >> 3;
lrclk_div_val = lrclk_div_val << 3;
break;
case 32:
bclk_div_val = bclk_div_val >> 4;
lrclk_div_val = lrclk_div_val << 4;
break;
default:
dev_err(dev, "Unsupported channels %#x\n",
params_channels(params));
}
break;
default:
break;
}
adata->lrclk_div = lrclk_div_val;
adata->bclk_div = bclk_div_val;
}
Expand All @@ -321,16 +401,16 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
switch (dai->driver->id) {
case I2S_BT_INSTANCE:
water_val = ACP_BT_TX_INTR_WATERMARK_SIZE;
water_val = ACP_BT_TX_INTR_WATERMARK_SIZE(adata);
reg_val = ACP_BTTDM_ITER;
ier_val = ACP_BTTDM_IER;
buf_reg = ACP_BT_TX_RINGBUFSIZE;
buf_reg = ACP_BT_TX_RINGBUFSIZE(adata);
break;
case I2S_SP_INSTANCE:
water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE;
water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE(adata);
reg_val = ACP_I2STDM_ITER;
ier_val = ACP_I2STDM_IER;
buf_reg = ACP_I2S_TX_RINGBUFSIZE;
buf_reg = ACP_I2S_TX_RINGBUFSIZE(adata);
break;
case I2S_HS_INSTANCE:
water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
Expand All @@ -345,16 +425,16 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
} else {
switch (dai->driver->id) {
case I2S_BT_INSTANCE:
water_val = ACP_BT_RX_INTR_WATERMARK_SIZE;
water_val = ACP_BT_RX_INTR_WATERMARK_SIZE(adata);
reg_val = ACP_BTTDM_IRER;
ier_val = ACP_BTTDM_IER;
buf_reg = ACP_BT_RX_RINGBUFSIZE;
buf_reg = ACP_BT_RX_RINGBUFSIZE(adata);
break;
case I2S_SP_INSTANCE:
water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE;
water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE(adata);
reg_val = ACP_I2STDM_IRER;
ier_val = ACP_I2STDM_IER;
buf_reg = ACP_I2S_RX_RINGBUFSIZE;
buf_reg = ACP_I2S_RX_RINGBUFSIZE(adata);
break;
case I2S_HS_INSTANCE:
water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
Expand All @@ -367,6 +447,7 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
return -EINVAL;
}
}

writel(period_bytes, adata->acp_base + water_val);
writel(buf_size, adata->acp_base + buf_reg);
if (rsrc->soc_mclk)
Expand Down Expand Up @@ -436,52 +517,67 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
{
struct device *dev = dai->component->dev;
struct acp_dev_data *adata = dev_get_drvdata(dev);
struct acp_chip_info *chip;
struct acp_resource *rsrc = adata->rsrc;
struct acp_stream *stream = substream->runtime->private_data;
u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0;
u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl;
unsigned int dir = substream->stream;

chip = dev_get_platdata(dev);
switch (dai->driver->id) {
case I2S_SP_INSTANCE:
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
reg_dma_size = ACP_I2S_TX_DMA_SIZE;
reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata);
acp_fifo_addr = rsrc->sram_pte_offset +
SP_PB_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_I2S_TX_FIFOADDR;
reg_fifo_size = ACP_I2S_TX_FIFOSIZE;

phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR);
reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata);
reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata);

if (chip->acp_rev >= ACP70_DEV)
phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START;
else
phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata));
} else {
reg_dma_size = ACP_I2S_RX_DMA_SIZE;
reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata);
acp_fifo_addr = rsrc->sram_pte_offset +
SP_CAPT_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_I2S_RX_FIFOADDR;
reg_fifo_size = ACP_I2S_RX_FIFOSIZE;
phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR);
reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata);
reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata);

if (chip->acp_rev >= ACP70_DEV)
phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START;
else
phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata));
}
break;
case I2S_BT_INSTANCE:
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
reg_dma_size = ACP_BT_TX_DMA_SIZE;
reg_dma_size = ACP_BT_TX_DMA_SIZE(adata);
acp_fifo_addr = rsrc->sram_pte_offset +
BT_PB_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_BT_TX_FIFOADDR;
reg_fifo_size = ACP_BT_TX_FIFOSIZE;

phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR);
reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata);
reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata);

if (chip->acp_rev >= ACP70_DEV)
phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START;
else
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata));
} else {
reg_dma_size = ACP_BT_RX_DMA_SIZE;
reg_dma_size = ACP_BT_RX_DMA_SIZE(adata);
acp_fifo_addr = rsrc->sram_pte_offset +
BT_CAPT_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_BT_RX_FIFOADDR;
reg_fifo_size = ACP_BT_RX_FIFOSIZE;

phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR);
reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata);
reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata);

if (chip->acp_rev >= ACP70_DEV)
phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START;
else
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata));
}
break;
case I2S_HS_INSTANCE:
Expand All @@ -492,7 +588,10 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
reg_fifo_addr = ACP_HS_TX_FIFOADDR;
reg_fifo_size = ACP_HS_TX_FIFOSIZE;

phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
if (chip->acp_rev >= ACP70_DEV)
phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START;
else
phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);
} else {
reg_dma_size = ACP_HS_RX_DMA_SIZE;
Expand All @@ -501,7 +600,10 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
reg_fifo_addr = ACP_HS_RX_FIFOADDR;
reg_fifo_size = ACP_HS_RX_FIFOSIZE;

phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
if (chip->acp_rev >= ACP70_DEV)
phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START;
else
phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);
}
break;
Expand Down
32 changes: 16 additions & 16 deletions sound/soc/amd/acp/acp-legacy-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,40 +113,40 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
switch (dai->driver->id) {
case I2S_SP_INSTANCE:
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
reg_dma_size = ACP_I2S_TX_DMA_SIZE;
reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata);
acp_fifo_addr = rsrc->sram_pte_offset +
SP_PB_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_I2S_TX_FIFOADDR;
reg_fifo_size = ACP_I2S_TX_FIFOSIZE;
reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata);
reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata);
phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR);
writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata));
} else {
reg_dma_size = ACP_I2S_RX_DMA_SIZE;
reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata);
acp_fifo_addr = rsrc->sram_pte_offset +
SP_CAPT_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_I2S_RX_FIFOADDR;
reg_fifo_size = ACP_I2S_RX_FIFOSIZE;
reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata);
reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata);
phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR);
writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata));
}
break;
case I2S_BT_INSTANCE:
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
reg_dma_size = ACP_BT_TX_DMA_SIZE;
reg_dma_size = ACP_BT_TX_DMA_SIZE(adata);
acp_fifo_addr = rsrc->sram_pte_offset +
BT_PB_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_BT_TX_FIFOADDR;
reg_fifo_size = ACP_BT_TX_FIFOSIZE;
reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata);
reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata);
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR);
writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata));
} else {
reg_dma_size = ACP_BT_RX_DMA_SIZE;
reg_dma_size = ACP_BT_RX_DMA_SIZE(adata);
acp_fifo_addr = rsrc->sram_pte_offset +
BT_CAPT_FIFO_ADDR_OFFSET;
reg_fifo_addr = ACP_BT_RX_FIFOADDR;
reg_fifo_size = ACP_BT_RX_FIFOSIZE;
reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata);
reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata);
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR);
writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata));
}
break;
case I2S_HS_INSTANCE:
Expand Down
7 changes: 6 additions & 1 deletion sound/soc/amd/acp/acp-pdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream,
struct acp_stream *stream = substream->runtime->private_data;
struct device *dev = dai->component->dev;
struct acp_dev_data *adata = dev_get_drvdata(dev);
struct acp_chip_info *chip;
u32 physical_addr, size_dmic, period_bytes;
unsigned int dmic_ctrl;

chip = dev_get_platdata(dev);
/* Enable default DMIC clk */
writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL);
dmic_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL);
Expand All @@ -45,7 +47,10 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream,
size_dmic = frames_to_bytes(substream->runtime,
substream->runtime->buffer_size);

physical_addr = stream->reg_offset + MEM_WINDOW_START;
if (chip->acp_rev >= ACP70_DEV)
physical_addr = ACP7x_DMIC_MEM_WINDOW_START;
else
physical_addr = stream->reg_offset + MEM_WINDOW_START;

/* Init DMIC Ring buffer */
writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR);
Expand Down
Loading

0 comments on commit 1324e5f

Please sign in to comment.