Unverified Commit 1324e5ff authored by Mark Brown's avatar Mark Brown
Browse files

Add i2s/tdm support for acp7.0 and acp7.1 platforms

Merge series from Venkata Prasad Potturu <venkataprasad.potturu@amd.com>:

1. Refactor acp generic driver to support all platforms.
2. Add i2s/tdm and support for acp7.0  and acp7.1 platforms.
parents 56f97d4d 3f600592
Loading
Loading
Loading
Loading
+145 −43
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
	}
@@ -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;
@@ -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;
@@ -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)
@@ -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:
@@ -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 {
@@ -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);
		}
+16 −16
Original line number Diff line number Diff line
@@ -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:
+6 −1
Original line number Diff line number Diff line
@@ -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);
@@ -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 */
+103 −14
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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 */
@@ -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;

@@ -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) {
+53 −20
Original line number Diff line number Diff line
@@ -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[] = {
@@ -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,
},
@@ -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,
},
@@ -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,
},
@@ -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) {
@@ -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