Loading sound/soc/amd/acp/acp-i2s.c +145 −43 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -116,6 +120,9 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas return -EINVAL; } switch (chip->acp_rev) { case ACP3X_DEV: case ACP6X_DEV: switch (slots) { case 1 ... 7: no_of_slots = slots; Loading @@ -127,17 +134,55 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas dev_err(dev, "Unsupported slots %d\n", slots); return -EINVAL; } break; 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, "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) { 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] = 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; Loading Loading @@ -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; } Loading @@ -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; Loading @@ -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; Loading @@ -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) Loading Loading @@ -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; 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); 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); 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); 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); 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); 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); 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); writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata)); } break; case I2S_HS_INSTANCE: Loading @@ -492,6 +588,9 @@ 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; 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 { Loading @@ -501,6 +600,9 @@ 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; 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); } Loading sound/soc/amd/acp/acp-legacy-common.c +16 −16 Original line number Diff line number Diff line Loading @@ -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: Loading sound/soc/amd/acp/acp-pdm.c +6 −1 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -45,6 +47,9 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream, size_dmic = frames_to_bytes(substream->runtime, substream->runtime->buffer_size); 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 */ Loading sound/soc/amd/acp/acp-platform.c +103 −14 Original line number Diff line number Diff line Loading @@ -68,6 +68,46 @@ static const struct snd_pcm_hardware acp_pcm_hardware_capture = { .periods_max = CAPTURE_MAX_NUM_PERIODS, }; static const struct snd_pcm_hardware acp6x_pcm_hardware_playback = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 32, .rates = SNDRV_PCM_RATE_8000_192000, .rate_min = 8000, .rate_max = 192000, .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE, .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE, .periods_min = PLAYBACK_MIN_NUM_PERIODS, .periods_max = PLAYBACK_MAX_NUM_PERIODS, }; static const struct snd_pcm_hardware acp6x_pcm_hardware_capture = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 32, .rates = SNDRV_PCM_RATE_8000_192000, .rate_min = 8000, .rate_max = 192000, .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, .periods_min = CAPTURE_MIN_NUM_PERIODS, .periods_max = CAPTURE_MAX_NUM_PERIODS, }; int acp_machine_select(struct acp_dev_data *adata) { struct snd_soc_acpi_mach *mach; Loading Loading @@ -137,17 +177,20 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream) { struct acp_resource *rsrc = adata->rsrc; u32 pte_reg, pte_size, reg_val; u32 reg_val; /* Use ATU base Group5 */ pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_5; pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5; reg_val = rsrc->sram_pte_offset; stream->reg_offset = 0x02000000; /* Group Enable */ reg_val = rsrc->sram_pte_offset; writel(reg_val | BIT(31), adata->acp_base + pte_reg); writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + pte_size); writel((reg_val + GRP1_OFFSET) | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_1); writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); writel((reg_val + GRP2_OFFSET) | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_2); writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2); writel(reg_val | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_5); writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5); writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); } EXPORT_SYMBOL_NS_GPL(config_pte_for_stream, SND_SOC_ACP_COMMON); Loading @@ -161,7 +204,40 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s u32 low, high, val; u16 page_idx; switch (adata->platform) { case ACP70: case ACP71: switch (stream->dai_id) { case I2S_SP_INSTANCE: if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) val = 0x0; else val = 0x1000; break; case I2S_BT_INSTANCE: if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) val = 0x2000; else val = 0x3000; break; case I2S_HS_INSTANCE: if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) val = 0x4000; else val = 0x5000; break; case DMIC_INSTANCE: val = 0x6000; break; default: dev_err(adata->dev, "Invalid dai id %x\n", stream->dai_id); break; } break; default: val = stream->pte_offset; break; } for (page_idx = 0; page_idx < num_pages; page_idx++) { /* Load the low address of page int ACP SRAM through SRBM */ Loading @@ -183,6 +259,7 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs struct snd_pcm_runtime *runtime = substream->runtime; struct device *dev = component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); struct acp_chip_info *chip; struct acp_stream *stream; int ret; Loading @@ -191,11 +268,23 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs return -ENOMEM; stream->substream = substream; chip = dev_get_platdata(dev); switch (chip->acp_rev) { case ACP63_DEV: case ACP70_DEV: case ACP71_DEV: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) runtime->hw = acp6x_pcm_hardware_playback; else runtime->hw = acp6x_pcm_hardware_capture; break; default: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) runtime->hw = acp_pcm_hardware_playback; else runtime->hw = acp_pcm_hardware_capture; break; } ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, DMA_SIZE); if (ret) { Loading sound/soc/amd/acp/acp70.c +53 −20 Original line number Diff line number Diff line Loading @@ -25,14 +25,17 @@ #define DRV_NAME "acp_asoc_acp70" #define CLK7_CLK0_DFS_CNTL_N1 0X0006C1A4 #define CLK0_DIVIDER 0X19 static struct acp_resource rsrc = { .offset = 0, .no_of_ctrls = 2, .irqp_used = 1, .soc_mclk = true, .irq_reg_offset = 0x1a00, .scratch_reg_offset = 0x12800, .sram_pte_offset = 0x03802800, .scratch_reg_offset = 0x10000, .sram_pte_offset = 0x03800000, }; static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines[] = { Loading @@ -49,23 +52,23 @@ static struct snd_soc_dai_driver acp70_dai[] = { .id = I2S_SP_INSTANCE, .playback = { .stream_name = "I2S SP Playback", .rates = SNDRV_PCM_RATE_8000_96000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .channels_max = 32, .rate_min = 8000, .rate_max = 96000, .rate_max = 192000, }, .capture = { .stream_name = "I2S SP Capture", .rates = SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .channels_max = 32, .rate_min = 8000, .rate_max = 48000, .rate_max = 192000, }, .ops = &asoc_acp_cpu_dai_ops, }, Loading @@ -74,23 +77,23 @@ static struct snd_soc_dai_driver acp70_dai[] = { .id = I2S_BT_INSTANCE, .playback = { .stream_name = "I2S BT Playback", .rates = SNDRV_PCM_RATE_8000_96000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .channels_max = 32, .rate_min = 8000, .rate_max = 96000, .rate_max = 192000, }, .capture = { .stream_name = "I2S BT Capture", .rates = SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .channels_max = 32, .rate_min = 8000, .rate_max = 48000, .rate_max = 192000, }, .ops = &asoc_acp_cpu_dai_ops, }, Loading @@ -99,23 +102,23 @@ static struct snd_soc_dai_driver acp70_dai[] = { .id = I2S_HS_INSTANCE, .playback = { .stream_name = "I2S HS Playback", .rates = SNDRV_PCM_RATE_8000_96000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .channels_max = 32, .rate_min = 8000, .rate_max = 96000, .rate_max = 192000, }, .capture = { .stream_name = "I2S HS Capture", .rates = SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .channels_max = 32, .rate_min = 8000, .rate_max = 48000, .rate_max = 192000, }, .ops = &asoc_acp_cpu_dai_ops, }, Loading @@ -134,12 +137,36 @@ static struct snd_soc_dai_driver acp70_dai[] = { }, }; static int acp70_i2s_master_clock_generate(struct acp_dev_data *adata) { struct pci_dev *smn_dev; u32 device_id; if (adata->platform == ACP70) device_id = 0x1507; else if (adata->platform == ACP71) device_id = 0x1122; else return -ENODEV; smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, device_id, NULL); if (!smn_dev) return -ENODEV; /* Set clk7 DFS clock divider register value to get mclk as 196.608MHz*/ smn_write(smn_dev, CLK7_CLK0_DFS_CNTL_N1, CLK0_DIVIDER); return 0; } static int acp_acp70_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_chip_info *chip; struct acp_dev_data *adata; struct resource *res; int ret; chip = dev_get_platdata(&pdev->dev); if (!chip || !chip->base) { Loading Loading @@ -191,6 +218,12 @@ static int acp_acp70_audio_probe(struct platform_device *pdev) acp_machine_select(adata); dev_set_drvdata(dev, adata); ret = acp70_i2s_master_clock_generate(adata); if (ret) { dev_err(&pdev->dev, "Failed to set I2S master clock as 196.608MHz\n"); return ret; } acp_enable_interrupts(adata); acp_platform_register(dev); pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); Loading Loading
sound/soc/amd/acp/acp-i2s.c +145 −43 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -116,6 +120,9 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas return -EINVAL; } switch (chip->acp_rev) { case ACP3X_DEV: case ACP6X_DEV: switch (slots) { case 1 ... 7: no_of_slots = slots; Loading @@ -127,17 +134,55 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas dev_err(dev, "Unsupported slots %d\n", slots); return -EINVAL; } break; 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, "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) { 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] = 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; Loading Loading @@ -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; } Loading @@ -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; Loading @@ -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; Loading @@ -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) Loading Loading @@ -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; 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); 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); 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); 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); 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); 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); 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); writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata)); } break; case I2S_HS_INSTANCE: Loading @@ -492,6 +588,9 @@ 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; 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 { Loading @@ -501,6 +600,9 @@ 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; 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); } Loading
sound/soc/amd/acp/acp-legacy-common.c +16 −16 Original line number Diff line number Diff line Loading @@ -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: Loading
sound/soc/amd/acp/acp-pdm.c +6 −1 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -45,6 +47,9 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream, size_dmic = frames_to_bytes(substream->runtime, substream->runtime->buffer_size); 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 */ Loading
sound/soc/amd/acp/acp-platform.c +103 −14 Original line number Diff line number Diff line Loading @@ -68,6 +68,46 @@ static const struct snd_pcm_hardware acp_pcm_hardware_capture = { .periods_max = CAPTURE_MAX_NUM_PERIODS, }; static const struct snd_pcm_hardware acp6x_pcm_hardware_playback = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 32, .rates = SNDRV_PCM_RATE_8000_192000, .rate_min = 8000, .rate_max = 192000, .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE, .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE, .periods_min = PLAYBACK_MIN_NUM_PERIODS, .periods_max = PLAYBACK_MAX_NUM_PERIODS, }; static const struct snd_pcm_hardware acp6x_pcm_hardware_capture = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 32, .rates = SNDRV_PCM_RATE_8000_192000, .rate_min = 8000, .rate_max = 192000, .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, .periods_min = CAPTURE_MIN_NUM_PERIODS, .periods_max = CAPTURE_MAX_NUM_PERIODS, }; int acp_machine_select(struct acp_dev_data *adata) { struct snd_soc_acpi_mach *mach; Loading Loading @@ -137,17 +177,20 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream) { struct acp_resource *rsrc = adata->rsrc; u32 pte_reg, pte_size, reg_val; u32 reg_val; /* Use ATU base Group5 */ pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_5; pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5; reg_val = rsrc->sram_pte_offset; stream->reg_offset = 0x02000000; /* Group Enable */ reg_val = rsrc->sram_pte_offset; writel(reg_val | BIT(31), adata->acp_base + pte_reg); writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + pte_size); writel((reg_val + GRP1_OFFSET) | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_1); writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); writel((reg_val + GRP2_OFFSET) | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_2); writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2); writel(reg_val | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_5); writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5); writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); } EXPORT_SYMBOL_NS_GPL(config_pte_for_stream, SND_SOC_ACP_COMMON); Loading @@ -161,7 +204,40 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s u32 low, high, val; u16 page_idx; switch (adata->platform) { case ACP70: case ACP71: switch (stream->dai_id) { case I2S_SP_INSTANCE: if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) val = 0x0; else val = 0x1000; break; case I2S_BT_INSTANCE: if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) val = 0x2000; else val = 0x3000; break; case I2S_HS_INSTANCE: if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) val = 0x4000; else val = 0x5000; break; case DMIC_INSTANCE: val = 0x6000; break; default: dev_err(adata->dev, "Invalid dai id %x\n", stream->dai_id); break; } break; default: val = stream->pte_offset; break; } for (page_idx = 0; page_idx < num_pages; page_idx++) { /* Load the low address of page int ACP SRAM through SRBM */ Loading @@ -183,6 +259,7 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs struct snd_pcm_runtime *runtime = substream->runtime; struct device *dev = component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); struct acp_chip_info *chip; struct acp_stream *stream; int ret; Loading @@ -191,11 +268,23 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs return -ENOMEM; stream->substream = substream; chip = dev_get_platdata(dev); switch (chip->acp_rev) { case ACP63_DEV: case ACP70_DEV: case ACP71_DEV: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) runtime->hw = acp6x_pcm_hardware_playback; else runtime->hw = acp6x_pcm_hardware_capture; break; default: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) runtime->hw = acp_pcm_hardware_playback; else runtime->hw = acp_pcm_hardware_capture; break; } ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, DMA_SIZE); if (ret) { Loading
sound/soc/amd/acp/acp70.c +53 −20 Original line number Diff line number Diff line Loading @@ -25,14 +25,17 @@ #define DRV_NAME "acp_asoc_acp70" #define CLK7_CLK0_DFS_CNTL_N1 0X0006C1A4 #define CLK0_DIVIDER 0X19 static struct acp_resource rsrc = { .offset = 0, .no_of_ctrls = 2, .irqp_used = 1, .soc_mclk = true, .irq_reg_offset = 0x1a00, .scratch_reg_offset = 0x12800, .sram_pte_offset = 0x03802800, .scratch_reg_offset = 0x10000, .sram_pte_offset = 0x03800000, }; static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines[] = { Loading @@ -49,23 +52,23 @@ static struct snd_soc_dai_driver acp70_dai[] = { .id = I2S_SP_INSTANCE, .playback = { .stream_name = "I2S SP Playback", .rates = SNDRV_PCM_RATE_8000_96000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .channels_max = 32, .rate_min = 8000, .rate_max = 96000, .rate_max = 192000, }, .capture = { .stream_name = "I2S SP Capture", .rates = SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .channels_max = 32, .rate_min = 8000, .rate_max = 48000, .rate_max = 192000, }, .ops = &asoc_acp_cpu_dai_ops, }, Loading @@ -74,23 +77,23 @@ static struct snd_soc_dai_driver acp70_dai[] = { .id = I2S_BT_INSTANCE, .playback = { .stream_name = "I2S BT Playback", .rates = SNDRV_PCM_RATE_8000_96000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .channels_max = 32, .rate_min = 8000, .rate_max = 96000, .rate_max = 192000, }, .capture = { .stream_name = "I2S BT Capture", .rates = SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .channels_max = 32, .rate_min = 8000, .rate_max = 48000, .rate_max = 192000, }, .ops = &asoc_acp_cpu_dai_ops, }, Loading @@ -99,23 +102,23 @@ static struct snd_soc_dai_driver acp70_dai[] = { .id = I2S_HS_INSTANCE, .playback = { .stream_name = "I2S HS Playback", .rates = SNDRV_PCM_RATE_8000_96000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .channels_max = 32, .rate_min = 8000, .rate_max = 96000, .rate_max = 192000, }, .capture = { .stream_name = "I2S HS Capture", .rates = SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .channels_max = 32, .rate_min = 8000, .rate_max = 48000, .rate_max = 192000, }, .ops = &asoc_acp_cpu_dai_ops, }, Loading @@ -134,12 +137,36 @@ static struct snd_soc_dai_driver acp70_dai[] = { }, }; static int acp70_i2s_master_clock_generate(struct acp_dev_data *adata) { struct pci_dev *smn_dev; u32 device_id; if (adata->platform == ACP70) device_id = 0x1507; else if (adata->platform == ACP71) device_id = 0x1122; else return -ENODEV; smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, device_id, NULL); if (!smn_dev) return -ENODEV; /* Set clk7 DFS clock divider register value to get mclk as 196.608MHz*/ smn_write(smn_dev, CLK7_CLK0_DFS_CNTL_N1, CLK0_DIVIDER); return 0; } static int acp_acp70_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_chip_info *chip; struct acp_dev_data *adata; struct resource *res; int ret; chip = dev_get_platdata(&pdev->dev); if (!chip || !chip->base) { Loading Loading @@ -191,6 +218,12 @@ static int acp_acp70_audio_probe(struct platform_device *pdev) acp_machine_select(adata); dev_set_drvdata(dev, adata); ret = acp70_i2s_master_clock_generate(adata); if (ret) { dev_err(&pdev->dev, "Failed to set I2S master clock as 196.608MHz\n"); return ret; } acp_enable_interrupts(adata); acp_platform_register(dev); pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); Loading