diff options
Diffstat (limited to 'sound/soc/amd/raven')
-rw-r--r-- | sound/soc/amd/raven/Makefile | 8 | ||||
-rw-r--r-- | sound/soc/amd/raven/acp3x-i2s.c | 339 | ||||
-rw-r--r-- | sound/soc/amd/raven/acp3x-pcm-dma.c | 539 | ||||
-rw-r--r-- | sound/soc/amd/raven/acp3x.h | 162 | ||||
-rw-r--r-- | sound/soc/amd/raven/chip_offset_byte.h | 639 | ||||
-rw-r--r-- | sound/soc/amd/raven/pci-acp3x.c | 358 |
6 files changed, 2045 insertions, 0 deletions
diff --git a/sound/soc/amd/raven/Makefile b/sound/soc/amd/raven/Makefile new file mode 100644 index 000000000..62c22b6ed --- /dev/null +++ b/sound/soc/amd/raven/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Raven Ridge platform Support +snd-pci-acp3x-objs := pci-acp3x.o +snd-acp3x-pcm-dma-objs := acp3x-pcm-dma.o +snd-acp3x-i2s-objs := acp3x-i2s.o +obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-pci-acp3x.o +obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-pcm-dma.o +obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-i2s.o diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c new file mode 100644 index 000000000..5bc028692 --- /dev/null +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// AMD ALSA SoC PCM Driver +// +//Copyright 2016 Advanced Micro Devices, Inc. + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> +#include <linux/dma-mapping.h> + +#include "acp3x.h" + +#define DRV_NAME "acp3x_i2s_playcap" + +static int acp3x_i2s_set_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct i2s_dev_data *adata; + int mode; + + adata = snd_soc_dai_get_drvdata(cpu_dai); + mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + switch (mode) { + case SND_SOC_DAIFMT_I2S: + adata->tdm_mode = TDM_DISABLE; + break; + case SND_SOC_DAIFMT_DSP_A: + adata->tdm_mode = TDM_ENABLE; + break; + default: + return -EINVAL; + } + return 0; +} + +static int acp3x_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, + u32 tx_mask, u32 rx_mask, int slots, int slot_width) +{ + struct i2s_dev_data *adata; + u32 frm_len; + u16 slot_len; + + adata = snd_soc_dai_get_drvdata(cpu_dai); + + /* These values are as per Hardware Spec */ + switch (slot_width) { + case SLOT_WIDTH_8: + slot_len = 8; + break; + case SLOT_WIDTH_16: + slot_len = 16; + break; + case SLOT_WIDTH_24: + slot_len = 24; + break; + case SLOT_WIDTH_32: + slot_len = 0; + break; + default: + return -EINVAL; + } + frm_len = FRM_LEN | (slots << 15) | (slot_len << 18); + adata->tdm_fmt = frm_len; + return 0; +} + +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; + struct i2s_dev_data *adata; + u32 val; + u32 reg_val, frmt_reg; + + prtd = asoc_substream_to_rtd(substream); + rtd = substream->runtime->private_data; + card = prtd->card; + adata = snd_soc_dai_get_drvdata(dai); + 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)) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_S8: + rtd->xfer_resolution = 0x0; + break; + case SNDRV_PCM_FORMAT_S16_LE: + rtd->xfer_resolution = 0x02; + break; + case SNDRV_PCM_FORMAT_S24_LE: + rtd->xfer_resolution = 0x04; + break; + case SNDRV_PCM_FORMAT_S32_LE: + rtd->xfer_resolution = 0x05; + break; + default: + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (rtd->i2s_instance) { + case I2S_BT_INSTANCE: + reg_val = mmACP_BTTDM_ITER; + frmt_reg = mmACP_BTTDM_TXFRMT; + break; + case I2S_SP_INSTANCE: + default: + reg_val = mmACP_I2STDM_ITER; + frmt_reg = mmACP_I2STDM_TXFRMT; + } + } else { + switch (rtd->i2s_instance) { + case I2S_BT_INSTANCE: + reg_val = mmACP_BTTDM_IRER; + frmt_reg = mmACP_BTTDM_RXFRMT; + break; + case I2S_SP_INSTANCE: + default: + reg_val = mmACP_I2STDM_IRER; + frmt_reg = mmACP_I2STDM_RXFRMT; + } + } + if (adata->tdm_mode) { + val = rv_readl(rtd->acp3x_base + reg_val); + rv_writel(val | 0x2, rtd->acp3x_base + reg_val); + rv_writel(adata->tdm_fmt, rtd->acp3x_base + frmt_reg); + } + val = rv_readl(rtd->acp3x_base + reg_val); + val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK; + val = val | (rtd->xfer_resolution << 3); + rv_writel(val, rtd->acp3x_base + reg_val); + return 0; +} + +static int acp3x_i2s_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct i2s_stream_instance *rtd; + u32 ret, val, period_bytes, reg_val, ier_val, water_val; + u32 buf_size, buf_reg; + + rtd = substream->runtime->private_data; + period_bytes = frames_to_bytes(substream->runtime, + substream->runtime->period_size); + buf_size = frames_to_bytes(substream->runtime, + substream->runtime->buffer_size); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + rtd->bytescount = acp_get_byte_count(rtd, + substream->stream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + 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; + buf_reg = mmACP_BT_TX_RINGBUFSIZE; + break; + case I2S_SP_INSTANCE: + default: + water_val = + mmACP_I2S_TX_INTR_WATERMARK_SIZE; + reg_val = mmACP_I2STDM_ITER; + ier_val = mmACP_I2STDM_IER; + buf_reg = mmACP_I2S_TX_RINGBUFSIZE; + } + } else { + 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; + buf_reg = mmACP_BT_RX_RINGBUFSIZE; + break; + case I2S_SP_INSTANCE: + default: + water_val = + mmACP_I2S_RX_INTR_WATERMARK_SIZE; + reg_val = mmACP_I2STDM_IRER; + ier_val = mmACP_I2STDM_IER; + buf_reg = mmACP_I2S_RX_RINGBUFSIZE; + } + } + rv_writel(period_bytes, rtd->acp3x_base + water_val); + rv_writel(buf_size, rtd->acp3x_base + buf_reg); + val = rv_readl(rtd->acp3x_base + reg_val); + val = val | BIT(0); + rv_writel(val, rtd->acp3x_base + reg_val); + rv_writel(1, rtd->acp3x_base + ier_val); + ret = 0; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + 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 & ~BIT(0); + rv_writel(val, rtd->acp3x_base + reg_val); + + if (!(rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER) & BIT(0)) && + !(rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER) & BIT(0))) + rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER); + if (!(rv_readl(rtd->acp3x_base + mmACP_I2STDM_ITER) & BIT(0)) && + !(rv_readl(rtd->acp3x_base + mmACP_I2STDM_IRER) & BIT(0))) + rv_writel(0, rtd->acp3x_base + mmACP_I2STDM_IER); + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static struct snd_soc_dai_ops acp3x_i2s_dai_ops = { + .hw_params = acp3x_i2s_hwparams, + .trigger = acp3x_i2s_trigger, + .set_fmt = acp3x_i2s_set_fmt, + .set_tdm_slot = acp3x_i2s_set_tdm_slot, +}; + +static const struct snd_soc_component_driver acp3x_dai_component = { + .name = DRV_NAME, +}; + +static struct snd_soc_dai_driver acp3x_i2s_dai = { + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .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 = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .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 = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + .ops = &acp3x_i2s_dai_ops, +}; + +static int acp3x_dai_probe(struct platform_device *pdev) +{ + struct resource *res; + struct i2s_dev_data *adata; + int ret; + + adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data), + GFP_KERNEL); + if (!adata) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); + return -ENOMEM; + } + adata->acp3x_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!adata->acp3x_base) + return -ENOMEM; + + adata->i2s_irq = res->start; + dev_set_drvdata(&pdev->dev, adata); + ret = devm_snd_soc_register_component(&pdev->dev, + &acp3x_dai_component, &acp3x_i2s_dai, 1); + if (ret) { + dev_err(&pdev->dev, "Fail to register acp i2s dai\n"); + return -ENODEV; + } + return 0; +} + +static int acp3x_dai_remove(struct platform_device *pdev) +{ + /* As we use devm_ memory alloc there is nothing TBD here */ + + return 0; +} + +static struct platform_driver acp3x_dai_driver = { + .probe = acp3x_dai_probe, + .remove = acp3x_dai_remove, + .driver = { + .name = "acp3x_i2s_playcap", + }, +}; + +module_platform_driver(acp3x_dai_driver); + +MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com"); +MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:"DRV_NAME); diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c new file mode 100644 index 000000000..01b283483 --- /dev/null +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// AMD ALSA SoC PCM Driver +// +//Copyright 2016 Advanced Micro Devices, Inc. + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/pm_runtime.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dai.h> + +#include "acp3x.h" + +#define DRV_NAME "acp3x_rv_i2s_dma" + +static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_BATCH | + 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 = 8, + .rates = SNDRV_PCM_RATE_8000_96000, + .rate_min = 8000, + .rate_max = 96000, + .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 acp3x_pcm_hardware_capture = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_BATCH | + 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 = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .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, +}; + +static irqreturn_t i2s_irq_handler(int irq, void *dev_id) +{ + struct i2s_dev_data *rv_i2s_data; + u16 play_flag, cap_flag; + u32 val; + + rv_i2s_data = dev_id; + if (!rv_i2s_data) + return IRQ_NONE; + + play_flag = 0; + cap_flag = 0; + val = rv_readl(rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT); + if ((val & BIT(BT_TX_THRESHOLD)) && rv_i2s_data->play_stream) { + rv_writel(BIT(BT_TX_THRESHOLD), rv_i2s_data->acp3x_base + + mmACP_EXTERNAL_INTR_STAT); + snd_pcm_period_elapsed(rv_i2s_data->play_stream); + play_flag = 1; + } + if ((val & BIT(I2S_TX_THRESHOLD)) && + rv_i2s_data->i2ssp_play_stream) { + rv_writel(BIT(I2S_TX_THRESHOLD), + rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT); + snd_pcm_period_elapsed(rv_i2s_data->i2ssp_play_stream); + play_flag = 1; + } + + if ((val & BIT(BT_RX_THRESHOLD)) && rv_i2s_data->capture_stream) { + rv_writel(BIT(BT_RX_THRESHOLD), rv_i2s_data->acp3x_base + + mmACP_EXTERNAL_INTR_STAT); + snd_pcm_period_elapsed(rv_i2s_data->capture_stream); + cap_flag = 1; + } + if ((val & BIT(I2S_RX_THRESHOLD)) && + rv_i2s_data->i2ssp_capture_stream) { + rv_writel(BIT(I2S_RX_THRESHOLD), + rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT); + snd_pcm_period_elapsed(rv_i2s_data->i2ssp_capture_stream); + cap_flag = 1; + } + + if (play_flag | cap_flag) + return IRQ_HANDLED; + else + return IRQ_NONE; +} + +static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction) +{ + u16 page_idx; + u32 low, high, val, acp_fifo_addr, reg_fifo_addr; + u32 reg_dma_size, reg_fifo_size; + dma_addr_t addr; + + 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); + rv_writel(PAGE_SIZE_4K_ENABLE, rtd->acp3x_base + + mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); + + for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) { + /* Load the low address of page int ACP SRAM through SRBM */ + low = lower_32_bits(addr); + high = upper_32_bits(addr); + + rv_writel(low, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val); + high |= BIT(31); + rv_writel(high, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val + + 4); + /* Move to next physically contiguos page */ + val += 8; + addr += PAGE_SIZE; + } + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + switch (rtd->i2s_instance) { + case I2S_BT_INSTANCE: + 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_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 { + switch (rtd->i2s_instance) { + case I2S_BT_INSTANCE: + 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; + + case I2S_SP_INSTANCE: + default: + 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(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, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + struct snd_soc_pcm_runtime *prtd; + struct i2s_dev_data *adata; + struct i2s_stream_instance *i2s_data; + int ret; + + runtime = substream->runtime; + prtd = asoc_substream_to_rtd(substream); + component = snd_soc_rtdcom_lookup(prtd, DRV_NAME); + adata = dev_get_drvdata(component->dev); + i2s_data = kzalloc(sizeof(*i2s_data), GFP_KERNEL); + if (!i2s_data) + return -EINVAL; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + runtime->hw = acp3x_pcm_hardware_playback; + else + runtime->hw = acp3x_pcm_hardware_capture; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + dev_err(component->dev, "set integer constraint failed\n"); + kfree(i2s_data); + return ret; + } + + i2s_data->acp3x_base = adata->acp3x_base; + runtime->private_data = i2s_data; + return ret; +} + + +static int acp3x_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct i2s_stream_instance *rtd; + struct snd_soc_pcm_runtime *prtd; + struct snd_soc_card *card; + struct acp3x_platform_info *pinfo; + struct i2s_dev_data *adata; + u64 size; + + prtd = asoc_substream_to_rtd(substream); + card = prtd->card; + pinfo = snd_soc_card_get_drvdata(card); + adata = dev_get_drvdata(component->dev); + 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; + switch (rtd->i2s_instance) { + case I2S_BT_INSTANCE: + adata->play_stream = substream; + break; + case I2S_SP_INSTANCE: + default: + adata->i2ssp_play_stream = substream; + } + } else { + rtd->i2s_instance = pinfo->cap_i2s_instance; + switch (rtd->i2s_instance) { + case I2S_BT_INSTANCE: + adata->capture_stream = substream; + break; + case I2S_SP_INSTANCE: + default: + adata->i2ssp_capture_stream = substream; + } + } + } else { + pr_err("pinfo failed\n"); + } + size = params_buffer_bytes(params); + rtd->dma_addr = substream->runtime->dma_addr; + rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT); + config_acp3x_dma(rtd, substream->stream); + return 0; +} + +static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct i2s_stream_instance *rtd; + u32 pos; + u32 buffersize; + u64 bytescount; + + rtd = substream->runtime->private_data; + + buffersize = frames_to_bytes(substream->runtime, + substream->runtime->buffer_size); + bytescount = acp_get_byte_count(rtd, substream->stream); + if (bytescount > rtd->bytescount) + bytescount -= rtd->bytescount; + pos = do_div(bytescount, buffersize); + return bytes_to_frames(substream->runtime, pos); +} + +static int acp3x_dma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + struct device *parent = component->dev->parent; + snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, + parent, MIN_BUFFER, MAX_BUFFER); + return 0; +} + +static int acp3x_dma_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return snd_pcm_lib_default_mmap(substream, vma); +} + +static int acp3x_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *prtd; + struct i2s_dev_data *adata; + struct i2s_stream_instance *ins; + + prtd = asoc_substream_to_rtd(substream); + component = snd_soc_rtdcom_lookup(prtd, DRV_NAME); + adata = dev_get_drvdata(component->dev); + ins = substream->runtime->private_data; + if (!ins) + return -EINVAL; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (ins->i2s_instance) { + case I2S_BT_INSTANCE: + adata->play_stream = NULL; + break; + case I2S_SP_INSTANCE: + default: + adata->i2ssp_play_stream = NULL; + } + } else { + switch (ins->i2s_instance) { + case I2S_BT_INSTANCE: + adata->capture_stream = NULL; + break; + case I2S_SP_INSTANCE: + default: + adata->i2ssp_capture_stream = NULL; + } + } + + return 0; +} + +static const struct snd_soc_component_driver acp3x_i2s_component = { + .name = DRV_NAME, + .open = acp3x_dma_open, + .close = acp3x_dma_close, + .hw_params = acp3x_dma_hw_params, + .pointer = acp3x_dma_pointer, + .mmap = acp3x_dma_mmap, + .pcm_construct = acp3x_dma_new, +}; + +static int acp3x_audio_probe(struct platform_device *pdev) +{ + struct resource *res; + struct i2s_dev_data *adata; + unsigned int irqflags; + int status; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "platform_data not retrieved\n"); + return -ENODEV; + } + irqflags = *((unsigned int *)(pdev->dev.platform_data)); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); + return -ENODEV; + } + + adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL); + if (!adata) + return -ENOMEM; + + adata->acp3x_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!adata->acp3x_base) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); + return -ENODEV; + } + + adata->i2s_irq = res->start; + + dev_set_drvdata(&pdev->dev, adata); + status = devm_snd_soc_register_component(&pdev->dev, + &acp3x_i2s_component, + NULL, 0); + if (status) { + dev_err(&pdev->dev, "Fail to register acp i2s component\n"); + return -ENODEV; + } + status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler, + irqflags, "ACP3x_I2S_IRQ", adata); + if (status) { + dev_err(&pdev->dev, "ACP3x I2S IRQ request failed\n"); + return -ENODEV; + } + + pm_runtime_set_autosuspend_delay(&pdev->dev, 2000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_allow(&pdev->dev); + return 0; +} + +static int acp3x_audio_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + return 0; +} + +static int acp3x_resume(struct device *dev) +{ + struct i2s_dev_data *adata; + u32 val, reg_val, frmt_val; + + reg_val = 0; + frmt_val = 0; + adata = dev_get_drvdata(dev); + + if (adata->play_stream && adata->play_stream->runtime) { + struct i2s_stream_instance *rtd = + adata->play_stream->runtime->private_data; + config_acp3x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK); + 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; + } + rv_writel((rtd->xfer_resolution << 3), + rtd->acp3x_base + reg_val); + } + 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); + 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); + } + if (adata->tdm_mode == TDM_ENABLE) { + rv_writel(adata->tdm_fmt, adata->acp3x_base + frmt_val); + val = rv_readl(adata->acp3x_base + reg_val); + rv_writel(val | 0x2, adata->acp3x_base + reg_val); + } + rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); + return 0; +} + + +static int acp3x_pcm_runtime_suspend(struct device *dev) +{ + struct i2s_dev_data *adata; + + adata = dev_get_drvdata(dev); + + rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); + + return 0; +} + +static int acp3x_pcm_runtime_resume(struct device *dev) +{ + struct i2s_dev_data *adata; + + adata = dev_get_drvdata(dev); + + rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); + return 0; +} + +static const struct dev_pm_ops acp3x_pm_ops = { + .runtime_suspend = acp3x_pcm_runtime_suspend, + .runtime_resume = acp3x_pcm_runtime_resume, + .resume = acp3x_resume, +}; + +static struct platform_driver acp3x_dma_driver = { + .probe = acp3x_audio_probe, + .remove = acp3x_audio_remove, + .driver = { + .name = "acp3x_rv_i2s_dma", + .pm = &acp3x_pm_ops, + }, +}; + +module_platform_driver(acp3x_dma_driver); + +MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com"); +MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:"DRV_NAME); diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h new file mode 100644 index 000000000..c3f0c8b75 --- /dev/null +++ b/sound/soc/amd/raven/acp3x.h @@ -0,0 +1,162 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ALSA SoC PCM Driver + * + * Copyright 2016 Advanced Micro Devices, Inc. + */ + +#include "chip_offset_byte.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 4 +#define ACP3x_PHY_BASE_ADDRESS 0x1240000 +#define ACP3x_I2S_MODE 0 +#define ACP3x_REG_START 0x1240000 +#define ACP3x_REG_END 0x1250200 +#define ACP3x_I2STDM_REG_START 0x1242400 +#define ACP3x_I2STDM_REG_END 0x1242410 +#define ACP3x_BT_TDM_REG_START 0x1242800 +#define ACP3x_BT_TDM_REG_END 0x1242810 +#define I2S_MODE 0x04 +#define I2S_RX_THRESHOLD 27 +#define I2S_TX_THRESHOLD 28 +#define BT_TX_THRESHOLD 26 +#define BT_RX_THRESHOLD 25 +#define ACP_ERR_INTR_MASK 29 +#define ACP3x_POWER_ON 0x00 +#define ACP3x_POWER_ON_IN_PROGRESS 0x01 +#define ACP3x_POWER_OFF 0x02 +#define ACP3x_POWER_OFF_IN_PROGRESS 0x03 +#define ACP3x_SOFT_RESET__SoftResetAudDone_MASK 0x00010001 + +#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 I2S_SP_TX_MEM_WINDOW_START 0x4000000 +#define I2S_SP_RX_MEM_WINDOW_START 0x4020000 +#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_MAX_NUM_PERIODS 8 +#define PLAYBACK_MAX_PERIOD_SIZE 8192 +#define PLAYBACK_MIN_PERIOD_SIZE 1024 +#define CAPTURE_MIN_NUM_PERIODS 2 +#define CAPTURE_MAX_NUM_PERIODS 8 +#define CAPTURE_MAX_PERIOD_SIZE 8192 +#define CAPTURE_MIN_PERIOD_SIZE 1024 + +#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS) +#define MIN_BUFFER MAX_BUFFER +#define FIFO_SIZE 0x100 +#define DMA_SIZE 0x40 +#define FRM_LEN 0x100 + +#define SLOT_WIDTH_8 0x08 +#define SLOT_WIDTH_16 0x10 +#define SLOT_WIDTH_24 0x18 +#define SLOT_WIDTH_32 0x20 +#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 +#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00 +#define ACP_PGFSM_STATUS_MASK 0x03 +#define ACP_POWERED_ON 0x00 +#define ACP_POWER_ON_IN_PROGRESS 0x01 +#define ACP_POWERED_OFF 0x02 +#define ACP_POWER_OFF_IN_PROGRESS 0x03 + +#define ACP3x_ITER_IRER_SAMP_LEN_MASK 0x38 +#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF + +struct acp3x_platform_info { + u16 play_i2s_instance; + u16 cap_i2s_instance; + u16 capture_channel; +}; + +struct i2s_dev_data { + bool tdm_mode; + unsigned int i2s_irq; + u16 i2s_instance; + u32 tdm_fmt; + u32 substream_type; + void __iomem *acp3x_base; + struct snd_pcm_substream *play_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 { + u16 num_pages; + u16 i2s_instance; + u16 capture_channel; + u16 direction; + u16 channels; + u32 xfer_resolution; + u32 val; + dma_addr_t dma_addr; + u64 bytescount; + void __iomem *acp3x_base; +}; + +static inline u32 rv_readl(void __iomem *base_addr) +{ + return readl(base_addr - ACP3x_PHY_BASE_ADDRESS); +} + +static inline void rv_writel(u32 val, void __iomem *base_addr) +{ + writel(val, base_addr - ACP3x_PHY_BASE_ADDRESS); +} + +static inline u64 acp_get_byte_count(struct i2s_stream_instance *rtd, + int direction) +{ + u64 byte_count; + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + switch (rtd->i2s_instance) { + case I2S_BT_INSTANCE: + byte_count = rv_readl(rtd->acp3x_base + + 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 { + switch (rtd->i2s_instance) { + case I2S_BT_INSTANCE: + byte_count = rv_readl(rtd->acp3x_base + + 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; +} diff --git a/sound/soc/amd/raven/chip_offset_byte.h b/sound/soc/amd/raven/chip_offset_byte.h new file mode 100644 index 000000000..9c1fac58f --- /dev/null +++ b/sound/soc/amd/raven/chip_offset_byte.h @@ -0,0 +1,639 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ACP 3.0 Register Documentation + * + * Copyright 2016 Advanced Micro Devices, Inc. + */ + +#ifndef _acp_ip_OFFSET_HEADER +#define _acp_ip_OFFSET_HEADER +// Registers from ACP_DMA block + +#define mmACP_DMA_CNTL_0 0x1240000 +#define mmACP_DMA_CNTL_1 0x1240004 +#define mmACP_DMA_CNTL_2 0x1240008 +#define mmACP_DMA_CNTL_3 0x124000C +#define mmACP_DMA_CNTL_4 0x1240010 +#define mmACP_DMA_CNTL_5 0x1240014 +#define mmACP_DMA_CNTL_6 0x1240018 +#define mmACP_DMA_CNTL_7 0x124001C +#define mmACP_DMA_DSCR_STRT_IDX_0 0x1240020 +#define mmACP_DMA_DSCR_STRT_IDX_1 0x1240024 +#define mmACP_DMA_DSCR_STRT_IDX_2 0x1240028 +#define mmACP_DMA_DSCR_STRT_IDX_3 0x124002C +#define mmACP_DMA_DSCR_STRT_IDX_4 0x1240030 +#define mmACP_DMA_DSCR_STRT_IDX_5 0x1240034 +#define mmACP_DMA_DSCR_STRT_IDX_6 0x1240038 +#define mmACP_DMA_DSCR_STRT_IDX_7 0x124003C +#define mmACP_DMA_DSCR_CNT_0 0x1240040 +#define mmACP_DMA_DSCR_CNT_1 0x1240044 +#define mmACP_DMA_DSCR_CNT_2 0x1240048 +#define mmACP_DMA_DSCR_CNT_3 0x124004C +#define mmACP_DMA_DSCR_CNT_4 0x1240050 +#define mmACP_DMA_DSCR_CNT_5 0x1240054 +#define mmACP_DMA_DSCR_CNT_6 0x1240058 +#define mmACP_DMA_DSCR_CNT_7 0x124005C +#define mmACP_DMA_PRIO_0 0x1240060 +#define mmACP_DMA_PRIO_1 0x1240064 +#define mmACP_DMA_PRIO_2 0x1240068 +#define mmACP_DMA_PRIO_3 0x124006C +#define mmACP_DMA_PRIO_4 0x1240070 +#define mmACP_DMA_PRIO_5 0x1240074 +#define mmACP_DMA_PRIO_6 0x1240078 +#define mmACP_DMA_PRIO_7 0x124007C +#define mmACP_DMA_CUR_DSCR_0 0x1240080 +#define mmACP_DMA_CUR_DSCR_1 0x1240084 +#define mmACP_DMA_CUR_DSCR_2 0x1240088 +#define mmACP_DMA_CUR_DSCR_3 0x124008C +#define mmACP_DMA_CUR_DSCR_4 0x1240090 +#define mmACP_DMA_CUR_DSCR_5 0x1240094 +#define mmACP_DMA_CUR_DSCR_6 0x1240098 +#define mmACP_DMA_CUR_DSCR_7 0x124009C +#define mmACP_DMA_CUR_TRANS_CNT_0 0x12400A0 +#define mmACP_DMA_CUR_TRANS_CNT_1 0x12400A4 +#define mmACP_DMA_CUR_TRANS_CNT_2 0x12400A8 +#define mmACP_DMA_CUR_TRANS_CNT_3 0x12400AC +#define mmACP_DMA_CUR_TRANS_CNT_4 0x12400B0 +#define mmACP_DMA_CUR_TRANS_CNT_5 0x12400B4 +#define mmACP_DMA_CUR_TRANS_CNT_6 0x12400B8 +#define mmACP_DMA_CUR_TRANS_CNT_7 0x12400BC +#define mmACP_DMA_ERR_STS_0 0x12400C0 +#define mmACP_DMA_ERR_STS_1 0x12400C4 +#define mmACP_DMA_ERR_STS_2 0x12400C8 +#define mmACP_DMA_ERR_STS_3 0x12400CC +#define mmACP_DMA_ERR_STS_4 0x12400D0 +#define mmACP_DMA_ERR_STS_5 0x12400D4 +#define mmACP_DMA_ERR_STS_6 0x12400D8 +#define mmACP_DMA_ERR_STS_7 0x12400DC +#define mmACP_DMA_DESC_BASE_ADDR 0x12400E0 +#define mmACP_DMA_DESC_MAX_NUM_DSCR 0x12400E4 +#define mmACP_DMA_CH_STS 0x12400E8 +#define mmACP_DMA_CH_GROUP 0x12400EC +#define mmACP_DMA_CH_RST_STS 0x12400F0 + + +// Registers from ACP_AXI2AXIATU block + +#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0x1240C00 +#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0x1240C04 +#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0x1240C08 +#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0x1240C0C +#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0x1240C10 +#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0x1240C14 +#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0x1240C18 +#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0x1240C1C +#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0x1240C20 +#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0x1240C24 +#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0x1240C28 +#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0x1240C2C +#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0x1240C30 +#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0x1240C34 +#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0x1240C38 +#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0x1240C3C +#define mmACPAXI2AXI_ATU_CTRL 0x1240C40 + + +// Registers from ACP_CLKRST block + +#define mmACP_SOFT_RESET 0x1241000 +#define mmACP_CONTROL 0x1241004 +#define mmACP_STATUS 0x1241008 +#define mmACP_DSP0_OCD_HALT_ON_RST 0x124100C +#define mmACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010 + + +// Registers from ACP_MISC block + +#define mmACP_EXTERNAL_INTR_ENB 0x1241800 +#define mmACP_EXTERNAL_INTR_CNTL 0x1241804 +#define mmACP_EXTERNAL_INTR_STAT 0x1241808 +#define mmACP_DSP0_INTR_CNTL 0x124180C +#define mmACP_DSP0_INTR_STAT 0x1241810 +#define mmACP_DSP_SW_INTR_CNTL 0x1241814 +#define mmACP_DSP_SW_INTR_STAT 0x1241818 +#define mmACP_SW_INTR_TRIG 0x124181C +#define mmACP_SMU_MAILBOX 0x1241820 +#define mmDSP_INTERRUPT_ROUTING_CTRL 0x1241824 +#define mmACP_DSP0_WATCHDOG_TIMER_CNTL 0x1241828 +#define mmACP_DSP0_EXT_TIMER1_CNTL 0x124182C +#define mmACP_DSP0_EXT_TIMER2_CNTL 0x1241830 +#define mmACP_DSP0_EXT_TIMER3_CNTL 0x1241834 +#define mmACP_DSP0_EXT_TIMER4_CNTL 0x1241838 +#define mmACP_DSP0_EXT_TIMER5_CNTL 0x124183C +#define mmACP_DSP0_EXT_TIMER6_CNTL 0x1241840 +#define mmACP_DSP0_EXT_TIMER1_CURR_VALUE 0x1241844 +#define mmACP_DSP0_EXT_TIMER2_CURR_VALUE 0x1241848 +#define mmACP_DSP0_EXT_TIMER3_CURR_VALUE 0x124184C +#define mmACP_DSP0_EXT_TIMER4_CURR_VALUE 0x1241850 +#define mmACP_DSP0_EXT_TIMER5_CURR_VALUE 0x1241854 +#define mmACP_DSP0_EXT_TIMER6_CURR_VALUE 0x1241858 +#define mmACP_FW_STATUS 0x124185C +#define mmACP_TIMER 0x1241874 +#define mmACP_TIMER_CNTL 0x1241878 +#define mmACP_PGMEM_CTRL 0x12418C0 +#define mmACP_ERROR_STATUS 0x12418C4 +#define mmACP_SW_I2S_ERROR_REASON 0x12418C8 +#define mmACP_MEM_PG_STS 0x12418CC + + +// Registers from ACP_PGFSM block + +#define mmACP_I2S_PIN_CONFIG 0x1241400 +#define mmACP_PAD_PULLUP_PULLDOWN_CTRL 0x1241404 +#define mmACP_PAD_DRIVE_STRENGTH_CTRL 0x1241408 +#define mmACP_SW_PAD_KEEPER_EN 0x124140C +#define mmACP_SW_WAKE_EN 0x1241410 +#define mmACP_I2S_WAKE_EN 0x1241414 +#define mmACP_PME_EN 0x1241418 +#define mmACP_PGFSM_CONTROL 0x124141C +#define mmACP_PGFSM_STATUS 0x1241420 + + +// Registers from ACP_SCRATCH block + +#define mmACP_SCRATCH_REG_0 0x1250000 +#define mmACP_SCRATCH_REG_1 0x1250004 +#define mmACP_SCRATCH_REG_2 0x1250008 +#define mmACP_SCRATCH_REG_3 0x125000C +#define mmACP_SCRATCH_REG_4 0x1250010 +#define mmACP_SCRATCH_REG_5 0x1250014 +#define mmACP_SCRATCH_REG_6 0x1250018 +#define mmACP_SCRATCH_REG_7 0x125001C +#define mmACP_SCRATCH_REG_8 0x1250020 +#define mmACP_SCRATCH_REG_9 0x1250024 +#define mmACP_SCRATCH_REG_10 0x1250028 +#define mmACP_SCRATCH_REG_11 0x125002C +#define mmACP_SCRATCH_REG_12 0x1250030 +#define mmACP_SCRATCH_REG_13 0x1250034 +#define mmACP_SCRATCH_REG_14 0x1250038 +#define mmACP_SCRATCH_REG_15 0x125003C +#define mmACP_SCRATCH_REG_16 0x1250040 +#define mmACP_SCRATCH_REG_17 0x1250044 +#define mmACP_SCRATCH_REG_18 0x1250048 +#define mmACP_SCRATCH_REG_19 0x125004C +#define mmACP_SCRATCH_REG_20 0x1250050 +#define mmACP_SCRATCH_REG_21 0x1250054 +#define mmACP_SCRATCH_REG_22 0x1250058 +#define mmACP_SCRATCH_REG_23 0x125005C +#define mmACP_SCRATCH_REG_24 0x1250060 +#define mmACP_SCRATCH_REG_25 0x1250064 +#define mmACP_SCRATCH_REG_26 0x1250068 +#define mmACP_SCRATCH_REG_27 0x125006C +#define mmACP_SCRATCH_REG_28 0x1250070 +#define mmACP_SCRATCH_REG_29 0x1250074 +#define mmACP_SCRATCH_REG_30 0x1250078 +#define mmACP_SCRATCH_REG_31 0x125007C +#define mmACP_SCRATCH_REG_32 0x1250080 +#define mmACP_SCRATCH_REG_33 0x1250084 +#define mmACP_SCRATCH_REG_34 0x1250088 +#define mmACP_SCRATCH_REG_35 0x125008C +#define mmACP_SCRATCH_REG_36 0x1250090 +#define mmACP_SCRATCH_REG_37 0x1250094 +#define mmACP_SCRATCH_REG_38 0x1250098 +#define mmACP_SCRATCH_REG_39 0x125009C +#define mmACP_SCRATCH_REG_40 0x12500A0 +#define mmACP_SCRATCH_REG_41 0x12500A4 +#define mmACP_SCRATCH_REG_42 0x12500A8 +#define mmACP_SCRATCH_REG_43 0x12500AC +#define mmACP_SCRATCH_REG_44 0x12500B0 +#define mmACP_SCRATCH_REG_45 0x12500B4 +#define mmACP_SCRATCH_REG_46 0x12500B8 +#define mmACP_SCRATCH_REG_47 0x12500BC +#define mmACP_SCRATCH_REG_48 0x12500C0 +#define mmACP_SCRATCH_REG_49 0x12500C4 +#define mmACP_SCRATCH_REG_50 0x12500C8 +#define mmACP_SCRATCH_REG_51 0x12500CC +#define mmACP_SCRATCH_REG_52 0x12500D0 +#define mmACP_SCRATCH_REG_53 0x12500D4 +#define mmACP_SCRATCH_REG_54 0x12500D8 +#define mmACP_SCRATCH_REG_55 0x12500DC +#define mmACP_SCRATCH_REG_56 0x12500E0 +#define mmACP_SCRATCH_REG_57 0x12500E4 +#define mmACP_SCRATCH_REG_58 0x12500E8 +#define mmACP_SCRATCH_REG_59 0x12500EC +#define mmACP_SCRATCH_REG_60 0x12500F0 +#define mmACP_SCRATCH_REG_61 0x12500F4 +#define mmACP_SCRATCH_REG_62 0x12500F8 +#define mmACP_SCRATCH_REG_63 0x12500FC +#define mmACP_SCRATCH_REG_64 0x1250100 +#define mmACP_SCRATCH_REG_65 0x1250104 +#define mmACP_SCRATCH_REG_66 0x1250108 +#define mmACP_SCRATCH_REG_67 0x125010C +#define mmACP_SCRATCH_REG_68 0x1250110 +#define mmACP_SCRATCH_REG_69 0x1250114 +#define mmACP_SCRATCH_REG_70 0x1250118 +#define mmACP_SCRATCH_REG_71 0x125011C +#define mmACP_SCRATCH_REG_72 0x1250120 +#define mmACP_SCRATCH_REG_73 0x1250124 +#define mmACP_SCRATCH_REG_74 0x1250128 +#define mmACP_SCRATCH_REG_75 0x125012C +#define mmACP_SCRATCH_REG_76 0x1250130 +#define mmACP_SCRATCH_REG_77 0x1250134 +#define mmACP_SCRATCH_REG_78 0x1250138 +#define mmACP_SCRATCH_REG_79 0x125013C +#define mmACP_SCRATCH_REG_80 0x1250140 +#define mmACP_SCRATCH_REG_81 0x1250144 +#define mmACP_SCRATCH_REG_82 0x1250148 +#define mmACP_SCRATCH_REG_83 0x125014C +#define mmACP_SCRATCH_REG_84 0x1250150 +#define mmACP_SCRATCH_REG_85 0x1250154 +#define mmACP_SCRATCH_REG_86 0x1250158 +#define mmACP_SCRATCH_REG_87 0x125015C +#define mmACP_SCRATCH_REG_88 0x1250160 +#define mmACP_SCRATCH_REG_89 0x1250164 +#define mmACP_SCRATCH_REG_90 0x1250168 +#define mmACP_SCRATCH_REG_91 0x125016C +#define mmACP_SCRATCH_REG_92 0x1250170 +#define mmACP_SCRATCH_REG_93 0x1250174 +#define mmACP_SCRATCH_REG_94 0x1250178 +#define mmACP_SCRATCH_REG_95 0x125017C +#define mmACP_SCRATCH_REG_96 0x1250180 +#define mmACP_SCRATCH_REG_97 0x1250184 +#define mmACP_SCRATCH_REG_98 0x1250188 +#define mmACP_SCRATCH_REG_99 0x125018C +#define mmACP_SCRATCH_REG_100 0x1250190 +#define mmACP_SCRATCH_REG_101 0x1250194 +#define mmACP_SCRATCH_REG_102 0x1250198 +#define mmACP_SCRATCH_REG_103 0x125019C +#define mmACP_SCRATCH_REG_104 0x12501A0 +#define mmACP_SCRATCH_REG_105 0x12501A4 +#define mmACP_SCRATCH_REG_106 0x12501A8 +#define mmACP_SCRATCH_REG_107 0x12501AC +#define mmACP_SCRATCH_REG_108 0x12501B0 +#define mmACP_SCRATCH_REG_109 0x12501B4 +#define mmACP_SCRATCH_REG_110 0x12501B8 +#define mmACP_SCRATCH_REG_111 0x12501BC +#define mmACP_SCRATCH_REG_112 0x12501C0 +#define mmACP_SCRATCH_REG_113 0x12501C4 +#define mmACP_SCRATCH_REG_114 0x12501C8 +#define mmACP_SCRATCH_REG_115 0x12501CC +#define mmACP_SCRATCH_REG_116 0x12501D0 +#define mmACP_SCRATCH_REG_117 0x12501D4 +#define mmACP_SCRATCH_REG_118 0x12501D8 +#define mmACP_SCRATCH_REG_119 0x12501DC +#define mmACP_SCRATCH_REG_120 0x12501E0 +#define mmACP_SCRATCH_REG_121 0x12501E4 +#define mmACP_SCRATCH_REG_122 0x12501E8 +#define mmACP_SCRATCH_REG_123 0x12501EC +#define mmACP_SCRATCH_REG_124 0x12501F0 +#define mmACP_SCRATCH_REG_125 0x12501F4 +#define mmACP_SCRATCH_REG_126 0x12501F8 +#define mmACP_SCRATCH_REG_127 0x12501FC +#define mmACP_SCRATCH_REG_128 0x1250200 + + +// Registers from ACP_SW_ACLK block + +#define mmSW_CORB_Base_Address 0x1243200 +#define mmSW_CORB_Write_Pointer 0x1243204 +#define mmSW_CORB_Read_Pointer 0x1243208 +#define mmSW_CORB_Control 0x124320C +#define mmSW_CORB_Size 0x1243214 +#define mmSW_RIRB_Base_Address 0x1243218 +#define mmSW_RIRB_Write_Pointer 0x124321C +#define mmSW_RIRB_Response_Interrupt_Count 0x1243220 +#define mmSW_RIRB_Control 0x1243224 +#define mmSW_RIRB_Size 0x1243228 +#define mmSW_RIRB_FIFO_MIN_THDL 0x124322C +#define mmSW_imm_cmd_UPPER_WORD 0x1243230 +#define mmSW_imm_cmd_LOWER_QWORD 0x1243234 +#define mmSW_imm_resp_UPPER_WORD 0x1243238 +#define mmSW_imm_resp_LOWER_QWORD 0x124323C +#define mmSW_imm_cmd_sts 0x1243240 +#define mmSW_BRA_BASE_ADDRESS 0x1243244 +#define mmSW_BRA_TRANSFER_SIZE 0x1243248 +#define mmSW_BRA_DMA_BUSY 0x124324C +#define mmSW_BRA_RESP 0x1243250 +#define mmSW_BRA_RESP_FRAME_ADDR 0x1243254 +#define mmSW_BRA_CURRENT_TRANSFER_SIZE 0x1243258 +#define mmSW_STATE_CHANGE_STATUS_0TO7 0x124325C +#define mmSW_STATE_CHANGE_STATUS_8TO11 0x1243260 +#define mmSW_STATE_CHANGE_STATUS_MASK_0to7 0x1243264 +#define mmSW_STATE_CHANGE_STATUS_MASK_8to11 0x1243268 +#define mmSW_CLK_FREQUENCY_CTRL 0x124326C +#define mmSW_ERROR_INTR_MASK 0x1243270 +#define mmSW_PHY_TEST_MODE_DATA_OFF 0x1243274 + + +// Registers from ACP_SW_SWCLK block + +#define mmACP_SW_EN 0x1243000 +#define mmACP_SW_EN_STATUS 0x1243004 +#define mmACP_SW_FRAMESIZE 0x1243008 +#define mmACP_SW_SSP_Counter 0x124300C +#define mmACP_SW_Audio_TX_EN 0x1243010 +#define mmACP_SW_Audio_TX_EN_STATUS 0x1243014 +#define mmACP_SW_Audio_TX_Frame_Format 0x1243018 +#define mmACP_SW_Audio_TX_SampleInterval 0x124301C +#define mmACP_SW_Audio_TX_Hctrl_DP0 0x1243020 +#define mmACP_SW_Audio_TX_Hctrl_DP1 0x1243024 +#define mmACP_SW_Audio_TX_Hctrl_DP2 0x1243028 +#define mmACP_SW_Audio_TX_Hctrl_DP3 0x124302C +#define mmACP_SW_Audio_TX_offset_DP0 0x1243030 +#define mmACP_SW_Audio_TX_offset_DP1 0x1243034 +#define mmACP_SW_Audio_TX_offset_DP2 0x1243038 +#define mmACP_SW_Audio_TX_offset_DP3 0x124303C +#define mmACP_SW_Audio_TX_Channel_Enable_DP0 0x1243040 +#define mmACP_SW_Audio_TX_Channel_Enable_DP1 0x1243044 +#define mmACP_SW_Audio_TX_Channel_Enable_DP2 0x1243048 +#define mmACP_SW_Audio_TX_Channel_Enable_DP3 0x124304C +#define mmACP_SW_BT_TX_EN 0x1243050 +#define mmACP_SW_BT_TX_EN_STATUS 0x1243054 +#define mmACP_SW_BT_TX_Frame_Format 0x1243058 +#define mmACP_SW_BT_TX_SampleInterval 0x124305C +#define mmACP_SW_BT_TX_Hctrl 0x1243060 +#define mmACP_SW_BT_TX_offset 0x1243064 +#define mmACP_SW_BT_TX_Channel_Enable_DP0 0x1243068 +#define mmACP_SW_Headset_TX_EN 0x124306C +#define mmACP_SW_Headset_TX_EN_STATUS 0x1243070 +#define mmACP_SW_Headset_TX_Frame_Format 0x1243074 +#define mmACP_SW_Headset_TX_SampleInterval 0x1243078 +#define mmACP_SW_Headset_TX_Hctrl 0x124307C +#define mmACP_SW_Headset_TX_offset 0x1243080 +#define mmACP_SW_Headset_TX_Channel_Enable_DP0 0x1243084 +#define mmACP_SW_Audio_RX_EN 0x1243088 +#define mmACP_SW_Audio_RX_EN_STATUS 0x124308C +#define mmACP_SW_Audio_RX_Frame_Format 0x1243090 +#define mmACP_SW_Audio_RX_SampleInterval 0x1243094 +#define mmACP_SW_Audio_RX_Hctrl_DP0 0x1243098 +#define mmACP_SW_Audio_RX_Hctrl_DP1 0x124309C +#define mmACP_SW_Audio_RX_Hctrl_DP2 0x1243100 +#define mmACP_SW_Audio_RX_Hctrl_DP3 0x1243104 +#define mmACP_SW_Audio_RX_offset_DP0 0x1243108 +#define mmACP_SW_Audio_RX_offset_DP1 0x124310C +#define mmACP_SW_Audio_RX_offset_DP2 0x1243110 +#define mmACP_SW_Audio_RX_offset_DP3 0x1243114 +#define mmACP_SW_Audio_RX_Channel_Enable_DP0 0x1243118 +#define mmACP_SW_Audio_RX_Channel_Enable_DP1 0x124311C +#define mmACP_SW_Audio_RX_Channel_Enable_DP2 0x1243120 +#define mmACP_SW_Audio_RX_Channel_Enable_DP3 0x1243124 +#define mmACP_SW_BT_RX_EN 0x1243128 +#define mmACP_SW_BT_RX_EN_STATUS 0x124312C +#define mmACP_SW_BT_RX_Frame_Format 0x1243130 +#define mmACP_SW_BT_RX_SampleInterval 0x1243134 +#define mmACP_SW_BT_RX_Hctrl 0x1243138 +#define mmACP_SW_BT_RX_offset 0x124313C +#define mmACP_SW_BT_RX_Channel_Enable_DP0 0x1243140 +#define mmACP_SW_Headset_RX_EN 0x1243144 +#define mmACP_SW_Headset_RX_EN_STATUS 0x1243148 +#define mmACP_SW_Headset_RX_Frame_Format 0x124314C +#define mmACP_SW_Headset_RX_SampleInterval 0x1243150 +#define mmACP_SW_Headset_RX_Hctrl 0x1243154 +#define mmACP_SW_Headset_RX_offset 0x1243158 +#define mmACP_SW_Headset_RX_Channel_Enable_DP0 0x124315C +#define mmACP_SW_BPT_PORT_EN 0x1243160 +#define mmACP_SW_BPT_PORT_EN_STATUS 0x1243164 +#define mmACP_SW_BPT_PORT_Frame_Format 0x1243168 +#define mmACP_SW_BPT_PORT_SampleInterval 0x124316C +#define mmACP_SW_BPT_PORT_Hctrl 0x1243170 +#define mmACP_SW_BPT_PORT_offset 0x1243174 +#define mmACP_SW_BPT_PORT_Channel_Enable 0x1243178 +#define mmACP_SW_BPT_PORT_First_byte_addr 0x124317C +#define mmACP_SW_CLK_RESUME_CTRL 0x1243180 +#define mmACP_SW_CLK_RESUME_Delay_Cntr 0x1243184 +#define mmACP_SW_BUS_RESET_CTRL 0x1243188 +#define mmACP_SW_PRBS_ERR_STATUS 0x124318C + + +// Registers from ACP_AUDIO_BUFFERS block + +#define mmACP_I2S_RX_RINGBUFADDR 0x1242000 +#define mmACP_I2S_RX_RINGBUFSIZE 0x1242004 +#define mmACP_I2S_RX_LINKPOSITIONCNTR 0x1242008 +#define mmACP_I2S_RX_FIFOADDR 0x124200C +#define mmACP_I2S_RX_FIFOSIZE 0x1242010 +#define mmACP_I2S_RX_DMA_SIZE 0x1242014 +#define mmACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x1242018 +#define mmACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x124201C +#define mmACP_I2S_RX_INTR_WATERMARK_SIZE 0x1242020 +#define mmACP_I2S_TX_RINGBUFADDR 0x1242024 +#define mmACP_I2S_TX_RINGBUFSIZE 0x1242028 +#define mmACP_I2S_TX_LINKPOSITIONCNTR 0x124202C +#define mmACP_I2S_TX_FIFOADDR 0x1242030 +#define mmACP_I2S_TX_FIFOSIZE 0x1242034 +#define mmACP_I2S_TX_DMA_SIZE 0x1242038 +#define mmACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x124203C +#define mmACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x1242040 +#define mmACP_I2S_TX_INTR_WATERMARK_SIZE 0x1242044 +#define mmACP_BT_RX_RINGBUFADDR 0x1242048 +#define mmACP_BT_RX_RINGBUFSIZE 0x124204C +#define mmACP_BT_RX_LINKPOSITIONCNTR 0x1242050 +#define mmACP_BT_RX_FIFOADDR 0x1242054 +#define mmACP_BT_RX_FIFOSIZE 0x1242058 +#define mmACP_BT_RX_DMA_SIZE 0x124205C +#define mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x1242060 +#define mmACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x1242064 +#define mmACP_BT_RX_INTR_WATERMARK_SIZE 0x1242068 +#define mmACP_BT_TX_RINGBUFADDR 0x124206C +#define mmACP_BT_TX_RINGBUFSIZE 0x1242070 +#define mmACP_BT_TX_LINKPOSITIONCNTR 0x1242074 +#define mmACP_BT_TX_FIFOADDR 0x1242078 +#define mmACP_BT_TX_FIFOSIZE 0x124207C +#define mmACP_BT_TX_DMA_SIZE 0x1242080 +#define mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x1242084 +#define mmACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x1242088 +#define mmACP_BT_TX_INTR_WATERMARK_SIZE 0x124208C +#define mmACP_HS_RX_RINGBUFADDR 0x1242090 +#define mmACP_HS_RX_RINGBUFSIZE 0x1242094 +#define mmACP_HS_RX_LINKPOSITIONCNTR 0x1242098 +#define mmACP_HS_RX_FIFOADDR 0x124209C +#define mmACP_HS_RX_FIFOSIZE 0x12420A0 +#define mmACP_HS_RX_DMA_SIZE 0x12420A4 +#define mmACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x12420A8 +#define mmACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x12420AC +#define mmACP_HS_RX_INTR_WATERMARK_SIZE 0x12420B0 +#define mmACP_HS_TX_RINGBUFADDR 0x12420B4 +#define mmACP_HS_TX_RINGBUFSIZE 0x12420B8 +#define mmACP_HS_TX_LINKPOSITIONCNTR 0x12420BC +#define mmACP_HS_TX_FIFOADDR 0x12420C0 +#define mmACP_HS_TX_FIFOSIZE 0x12420C4 +#define mmACP_HS_TX_DMA_SIZE 0x12420C8 +#define mmACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x12420CC +#define mmACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x12420D0 +#define mmACP_HS_TX_INTR_WATERMARK_SIZE 0x12420D4 + + +// Registers from ACP_I2S_TDM block + +#define mmACP_I2STDM_IER 0x1242400 +#define mmACP_I2STDM_IRER 0x1242404 +#define mmACP_I2STDM_RXFRMT 0x1242408 +#define mmACP_I2STDM_ITER 0x124240C +#define mmACP_I2STDM_TXFRMT 0x1242410 + + +// Registers from ACP_BT_TDM block + +#define mmACP_BTTDM_IER 0x1242800 +#define mmACP_BTTDM_IRER 0x1242804 +#define mmACP_BTTDM_RXFRMT 0x1242808 +#define mmACP_BTTDM_ITER 0x124280C +#define mmACP_BTTDM_TXFRMT 0x1242810 + + +// Registers from AZALIA_IP block + +#define mmAudio_Az_Global_Capabilities 0x1200000 +#define mmAudio_Az_Minor_Version 0x1200002 +#define mmAudio_Az_Major_Version 0x1200003 +#define mmAudio_Az_Output_Payload_Capability 0x1200004 +#define mmAudio_Az_Input_Payload_Capability 0x1200006 +#define mmAudio_Az_Global_Control 0x1200008 +#define mmAudio_Az_Wake_Enable 0x120000C +#define mmAudio_Az_State_Change_Status 0x120000E +#define mmAudio_Az_Global_Status 0x1200010 +#define mmAudio_Az_Linked_List_Capability_Header 0x1200014 +#define mmAudio_Az_Output_Stream_Payload_Capability 0x1200018 +#define mmAudio_Az_Input_Stream_Payload_Capability 0x120001A +#define mmAudio_Az_Interrupt_Control 0x1200020 +#define mmAudio_Az_Interrupt_Status 0x1200024 +#define mmAudio_Az_Wall_Clock_Counter 0x1200030 +#define mmAudio_Az_Stream_Synchronization 0x1200038 +#define mmAudio_Az_CORB_Lower_Base_Address 0x1200040 +#define mmAudio_Az_CORB_Upper_Base_Address 0x1200044 +#define mmAudio_Az_CORB_Write_Pointer 0x1200048 +#define mmAudio_Az_CORB_Read_Pointer 0x120004A +#define mmAudio_Az_CORB_Control 0x120004C +#define mmAudio_Az_CORB_Status 0x120004D +#define mmAudio_Az_CORB_Size 0x120004E +#define mmAudio_Az_RIRB_Lower_Base_Address 0x1200050 +#define mmAudio_Az_RIRB_Upper_Base_Address 0x1200054 +#define mmAudio_Az_RIRB_Write_Pointer 0x1200058 +#define mmAudio_Az_RIRB_Response_Interrupt_Count 0x120005A +#define mmAudio_Az_RIRB_Control 0x120005C +#define mmAudio_Az_RIRB_Status 0x120005D +#define mmAudio_Az_RIRB_Size 0x120005E +#define mmAudio_Az_Immediate_Command_Output_Interface 0x1200060 +#define mmAudio_Az_Immediate_Response_Input_Interface 0x1200064 +#define mmAudio_Az_Immediate_Command_Status 0x1200068 +#define mmAudio_Az_DPLBASE 0x1200070 +#define mmAudio_Az_DPUBASE 0x1200074 +#define mmAudio_Az_Input_SD0CTL_and_STS 0x1200080 +#define mmAudio_Az_Input_SD0LPIB 0x1200084 +#define mmAudio_Az_Input_SD0CBL 0x1200088 +#define mmAudio_Az_Input_SD0LVI 0x120008C +#define mmAudio_Az_Input_SD0FIFOS 0x1200090 +#define mmAudio_Az_Input_SD0FMT 0x1200092 +#define mmAudio_Az_Input_SD0BDPL 0x1200098 +#define mmAudio_Az_Input_SD0BDPU 0x120009C +#define mmAudio_Az_Input_SD1CTL_and_STS 0x12000A0 +#define mmAudio_Az_Input_SD1LPIB 0x12000A4 +#define mmAudio_Az_Input_SD1CBL 0x12000A8 +#define mmAudio_Az_Input_SD1LVI 0x12000AC +#define mmAudio_Az_Input_SD1FIFOS 0x12000B0 +#define mmAudio_Az_Input_SD1FMT 0x12000B2 +#define mmAudio_Az_Input_SD1BDPL 0x12000B8 +#define mmAudio_Az_Input_SD1BDPU 0x12000BC +#define mmAudio_Az_Input_SD2CTL_and_STS 0x12000C0 +#define mmAudio_Az_Input_SD2LPIB 0x12000C4 +#define mmAudio_Az_Input_SD2CBL 0x12000C8 +#define mmAudio_Az_Input_SD2LVI 0x12000CC +#define mmAudio_Az_Input_SD2FIFOS 0x12000D0 +#define mmAudio_Az_Input_SD2FMT 0x12000D2 +#define mmAudio_Az_Input_SD2BDPL 0x12000D8 +#define mmAudio_Az_Input_SD2BDPU 0x12000DC +#define mmAudio_Az_Input_SD3CTL_and_STS 0x12000E0 +#define mmAudio_Az_Input_SD3LPIB 0x12000E4 +#define mmAudio_Az_Input_SD3CBL 0x12000E8 +#define mmAudio_Az_Input_SD3LVI 0x12000EC +#define mmAudio_Az_Input_SD3FIFOS 0x12000F0 +#define mmAudio_Az_Input_SD3FMT 0x12000F2 +#define mmAudio_Az_Input_SD3BDPL 0x12000F8 +#define mmAudio_Az_Input_SD3BDPU 0x12000FC +#define mmAudio_Az_Output_SD0CTL_and_STS 0x1200100 +#define mmAudio_Az_Output_SD0LPIB 0x1200104 +#define mmAudio_Az_Output_SD0CBL 0x1200108 +#define mmAudio_Az_Output_SD0LVI 0x120010C +#define mmAudio_Az_Output_SD0FIFOS 0x1200110 +#define mmAudio_Az_Output_SD0FMT 0x1200112 +#define mmAudio_Az_Output_SD0BDPL 0x1200118 +#define mmAudio_Az_Output_SD0BDPU 0x120011C +#define mmAudio_Az_Output_SD1CTL_and_STS 0x1200120 +#define mmAudio_Az_Output_SD1LPIB 0x1200124 +#define mmAudio_Az_Output_SD1CBL 0x1200128 +#define mmAudio_Az_Output_SD1LVI 0x120012C +#define mmAudio_Az_Output_SD1FIFOS 0x1200130 +#define mmAudio_Az_Output_SD1FMT 0x1200132 +#define mmAudio_Az_Output_SD1BDPL 0x1200138 +#define mmAudio_Az_Output_SD1BDPU 0x120013C +#define mmAudio_Az_Output_SD2CTL_and_STS 0x1200140 +#define mmAudio_Az_Output_SD2LPIB 0x1200144 +#define mmAudio_Az_Output_SD2CBL 0x1200148 +#define mmAudio_Az_Output_SD2LVI 0x120014C +#define mmAudio_Az_Output_SD2FIFOS 0x1200150 +#define mmAudio_Az_Output_SD2FMT 0x1200152 +#define mmAudio_Az_Output_SD2BDPL 0x1200158 +#define mmAudio_Az_Output_SD2BDPU 0x120015C +#define mmAudio_Az_Output_SD3CTL_and_STS 0x1200160 +#define mmAudio_Az_Output_SD3LPIB 0x1200164 +#define mmAudio_Az_Output_SD3CBL 0x1200168 +#define mmAudio_Az_Output_SD3LVI 0x120016C +#define mmAudio_Az_Output_SD3FIFOS 0x1200170 +#define mmAudio_Az_Output_SD3FMT 0x1200172 +#define mmAudio_Az_Output_SD3BDPL 0x1200178 +#define mmAudio_Az_Output_SD3BDPU 0x120017C +#define mmAudioAZ_Misc_Control_Register_1 0x1200180 +#define mmAudioAZ_Misc_Control_Register_2 0x1200182 +#define mmAudioAZ_Misc_Control_Register_3 0x1200183 +#define mmAudio_AZ_Multiple_Links_Capability_Header 0x1200200 +#define mmAudio_AZ_Multiple_Links_Capability_Declaration 0x1200204 +#define mmAudio_AZ_Link0_Capabilities 0x1200240 +#define mmAudio_AZ_Link0_Control 0x1200244 +#define mmAudio_AZ_Link0_Output_Stream_ID 0x1200248 +#define mmAudio_AZ_Link0_SDI_Identifier 0x120024C +#define mmAudio_AZ_Link0_Per_Stream_Overhead 0x1200250 +#define mmAudio_AZ_Link0_Wall_Frame_Counter 0x1200258 +#define mmAudio_AZ_Link0_Output_Payload_Capability_L 0x1200260 +#define mmAudio_AZ_Link0_Output_Payload_Capability_U 0x1200264 +#define mmAudio_AZ_Link0_Input_Payload_Capability_L 0x1200270 +#define mmAudio_AZ_Link0_Input_Payload_Capability_U 0x1200274 +#define mmAudio_Az_Input_SD0LICBA 0x1202084 +#define mmAudio_Az_Input_SD1LICBA 0x12020A4 +#define mmAudio_Az_Input_SD2LICBA 0x12020C4 +#define mmAudio_Az_Input_SD3LICBA 0x12020E4 +#define mmAudio_Az_Output_SD0LICBA 0x1202104 +#define mmAudio_Az_Output_SD1LICBA 0x1202124 +#define mmAudio_Az_Output_SD2LICBA 0x1202144 +#define mmAudio_Az_Output_SD3LICBA 0x1202164 +#define mmAUDIO_AZ_POWER_MANAGEMENT_CONTROL 0x1204000 +#define mmAUDIO_AZ_IOC_SOFTRST_CONTROL 0x1204004 +#define mmAUDIO_AZ_IOC_CLKGATE_CONTROL 0x1204008 + + +// Registers from ACP_AZALIA block + +#define mmACP_AZ_PAGE0_LBASE_ADDR 0x1243800 +#define mmACP_AZ_PAGE0_UBASE_ADDR 0x1243804 +#define mmACP_AZ_PAGE0_PGEN_SIZE 0x1243808 +#define mmACP_AZ_PAGE0_OFFSET 0x124380C +#define mmACP_AZ_PAGE1_LBASE_ADDR 0x1243810 +#define mmACP_AZ_PAGE1_UBASE_ADDR 0x1243814 +#define mmACP_AZ_PAGE1_PGEN_SIZE 0x1243818 +#define mmACP_AZ_PAGE1_OFFSET 0x124381C +#define mmACP_AZ_PAGE2_LBASE_ADDR 0x1243820 +#define mmACP_AZ_PAGE2_UBASE_ADDR 0x1243824 +#define mmACP_AZ_PAGE2_PGEN_SIZE 0x1243828 +#define mmACP_AZ_PAGE2_OFFSET 0x124382C +#define mmACP_AZ_PAGE3_LBASE_ADDR 0x1243830 +#define mmACP_AZ_PAGE3_UBASE_ADDR 0x1243834 +#define mmACP_AZ_PAGE3_PGEN_SIZE 0x1243838 +#define mmACP_AZ_PAGE3_OFFSET 0x124383C +#define mmACP_AZ_PAGE4_LBASE_ADDR 0x1243840 +#define mmACP_AZ_PAGE4_UBASE_ADDR 0x1243844 +#define mmACP_AZ_PAGE4_PGEN_SIZE 0x1243848 +#define mmACP_AZ_PAGE4_OFFSET 0x124384C +#define mmACP_AZ_PAGE5_LBASE_ADDR 0x1243850 +#define mmACP_AZ_PAGE5_UBASE_ADDR 0x1243854 +#define mmACP_AZ_PAGE5_PGEN_SIZE 0x1243858 +#define mmACP_AZ_PAGE5_OFFSET 0x124385C +#define mmACP_AZ_PAGE6_LBASE_ADDR 0x1243860 +#define mmACP_AZ_PAGE6_UBASE_ADDR 0x1243864 +#define mmACP_AZ_PAGE6_PGEN_SIZE 0x1243868 +#define mmACP_AZ_PAGE6_OFFSET 0x124386C +#define mmACP_AZ_PAGE7_LBASE_ADDR 0x1243870 +#define mmACP_AZ_PAGE7_UBASE_ADDR 0x1243874 +#define mmACP_AZ_PAGE7_PGEN_SIZE 0x1243878 +#define mmACP_AZ_PAGE7_OFFSET 0x124387C + + +#endif diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c new file mode 100644 index 000000000..df83d2ce7 --- /dev/null +++ b/sound/soc/amd/raven/pci-acp3x.c @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// AMD ACP PCI Driver +// +//Copyright 2016 Advanced Micro Devices, Inc. + +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/pm_runtime.h> +#include <linux/delay.h> + +#include "acp3x.h" + +struct acp3x_dev_data { + void __iomem *acp3x_base; + bool acp3x_audio_mode; + struct resource *res; + struct platform_device *pdev[ACP3x_DEVS]; + u32 pme_en; +}; + +static int acp3x_power_on(struct acp3x_dev_data *adata) +{ + void __iomem *acp3x_base = adata->acp3x_base; + u32 val; + int timeout; + + val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS); + + if (val == 0) + return val; + + if (!((val & ACP_PGFSM_STATUS_MASK) == + ACP_POWER_ON_IN_PROGRESS)) + rv_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, + acp3x_base + mmACP_PGFSM_CONTROL); + timeout = 0; + while (++timeout < 500) { + val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS); + if (!val) { + /* ACP power On clears PME_EN. + * Restore the value to its prior state + */ + rv_writel(adata->pme_en, acp3x_base + mmACP_PME_EN); + return 0; + } + udelay(1); + } + return -ETIMEDOUT; +} + +static int acp3x_reset(void __iomem *acp3x_base) +{ + u32 val; + int timeout; + + rv_writel(1, acp3x_base + mmACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = rv_readl(acp3x_base + mmACP_SOFT_RESET); + if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) + break; + cpu_relax(); + } + rv_writel(0, acp3x_base + mmACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = rv_readl(acp3x_base + mmACP_SOFT_RESET); + if (!val) + return 0; + cpu_relax(); + } + return -ETIMEDOUT; +} + +static void acp3x_enable_interrupts(void __iomem *acp_base) +{ + rv_writel(0x01, acp_base + mmACP_EXTERNAL_INTR_ENB); +} + +static void acp3x_disable_interrupts(void __iomem *acp_base) +{ + rv_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + + mmACP_EXTERNAL_INTR_STAT); + rv_writel(0x00, acp_base + mmACP_EXTERNAL_INTR_CNTL); + rv_writel(0x00, acp_base + mmACP_EXTERNAL_INTR_ENB); +} + +static int acp3x_init(struct acp3x_dev_data *adata) +{ + void __iomem *acp3x_base = adata->acp3x_base; + int ret; + + /* power on */ + ret = acp3x_power_on(adata); + if (ret) { + pr_err("ACP3x power on failed\n"); + return ret; + } + /* Reset */ + ret = acp3x_reset(acp3x_base); + if (ret) { + pr_err("ACP3x reset failed\n"); + return ret; + } + acp3x_enable_interrupts(acp3x_base); + return 0; +} + +static int acp3x_deinit(void __iomem *acp3x_base) +{ + int ret; + + acp3x_disable_interrupts(acp3x_base); + /* Reset */ + ret = acp3x_reset(acp3x_base); + if (ret) { + pr_err("ACP3x reset failed\n"); + return ret; + } + return 0; +} + +static int snd_acp3x_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + struct acp3x_dev_data *adata; + struct platform_device_info pdevinfo[ACP3x_DEVS]; + unsigned int irqflags; + int ret, i; + u32 addr, val; + + /* Raven device detection */ + if (pci->revision != 0x00) + return -ENODEV; + + if (pci_enable_device(pci)) { + dev_err(&pci->dev, "pci_enable_device failed\n"); + return -ENODEV; + } + + ret = pci_request_regions(pci, "AMD ACP3x audio"); + if (ret < 0) { + dev_err(&pci->dev, "pci_request_regions failed\n"); + goto disable_pci; + } + + adata = devm_kzalloc(&pci->dev, sizeof(struct acp3x_dev_data), + GFP_KERNEL); + if (!adata) { + ret = -ENOMEM; + goto release_regions; + } + + /* check for msi interrupt support */ + ret = pci_enable_msi(pci); + if (ret) + /* msi is not enabled */ + irqflags = IRQF_SHARED; + else + /* msi is enabled */ + irqflags = 0; + + addr = pci_resource_start(pci, 0); + adata->acp3x_base = devm_ioremap(&pci->dev, addr, + pci_resource_len(pci, 0)); + if (!adata->acp3x_base) { + ret = -ENOMEM; + goto disable_msi; + } + pci_set_master(pci); + pci_set_drvdata(pci, adata); + /* Save ACP_PME_EN state */ + adata->pme_en = rv_readl(adata->acp3x_base + mmACP_PME_EN); + ret = acp3x_init(adata); + if (ret) + goto disable_msi; + + val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG); + switch (val) { + case I2S_MODE: + adata->res = devm_kzalloc(&pci->dev, + sizeof(struct resource) * 4, + GFP_KERNEL); + if (!adata->res) { + ret = -ENOMEM; + goto de_init; + } + + adata->res[0].name = "acp3x_i2s_iomem"; + adata->res[0].flags = IORESOURCE_MEM; + adata->res[0].start = addr; + adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START); + + adata->res[1].name = "acp3x_i2s_sp"; + adata->res[1].flags = IORESOURCE_MEM; + adata->res[1].start = addr + ACP3x_I2STDM_REG_START; + adata->res[1].end = addr + ACP3x_I2STDM_REG_END; + + adata->res[2].name = "acp3x_i2s_bt"; + adata->res[2].flags = IORESOURCE_MEM; + adata->res[2].start = addr + ACP3x_BT_TDM_REG_START; + adata->res[2].end = addr + ACP3x_BT_TDM_REG_END; + + adata->res[3].name = "acp3x_i2s_irq"; + adata->res[3].flags = IORESOURCE_IRQ; + adata->res[3].start = pci->irq; + adata->res[3].end = adata->res[3].start; + + adata->acp3x_audio_mode = ACP3x_I2S_MODE; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo[0].name = "acp3x_rv_i2s_dma"; + pdevinfo[0].id = 0; + pdevinfo[0].parent = &pci->dev; + pdevinfo[0].num_res = 4; + pdevinfo[0].res = &adata->res[0]; + pdevinfo[0].data = &irqflags; + pdevinfo[0].size_data = sizeof(irqflags); + + pdevinfo[1].name = "acp3x_i2s_playcap"; + pdevinfo[1].id = 0; + pdevinfo[1].parent = &pci->dev; + pdevinfo[1].num_res = 1; + pdevinfo[1].res = &adata->res[1]; + + pdevinfo[2].name = "acp3x_i2s_playcap"; + pdevinfo[2].id = 1; + pdevinfo[2].parent = &pci->dev; + pdevinfo[2].num_res = 1; + pdevinfo[2].res = &adata->res[1]; + + pdevinfo[3].name = "acp3x_i2s_playcap"; + pdevinfo[3].id = 2; + pdevinfo[3].parent = &pci->dev; + pdevinfo[3].num_res = 1; + pdevinfo[3].res = &adata->res[2]; + for (i = 0; i < ACP3x_DEVS; i++) { + adata->pdev[i] = + platform_device_register_full(&pdevinfo[i]); + if (IS_ERR(adata->pdev[i])) { + dev_err(&pci->dev, "cannot register %s device\n", + pdevinfo[i].name); + ret = PTR_ERR(adata->pdev[i]); + goto unregister_devs; + } + } + break; + default: + dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val); + ret = -ENODEV; + goto disable_msi; + } + pm_runtime_set_autosuspend_delay(&pci->dev, 2000); + pm_runtime_use_autosuspend(&pci->dev); + pm_runtime_put_noidle(&pci->dev); + pm_runtime_allow(&pci->dev); + return 0; + +unregister_devs: + if (val == I2S_MODE) + for (i = 0; i < ACP3x_DEVS; i++) + platform_device_unregister(adata->pdev[i]); +de_init: + if (acp3x_deinit(adata->acp3x_base)) + dev_err(&pci->dev, "ACP de-init failed\n"); +disable_msi: + pci_disable_msi(pci); +release_regions: + pci_release_regions(pci); +disable_pci: + pci_disable_device(pci); + + return ret; +} + +static int snd_acp3x_suspend(struct device *dev) +{ + int ret; + struct acp3x_dev_data *adata; + + adata = dev_get_drvdata(dev); + ret = acp3x_deinit(adata->acp3x_base); + if (ret) + dev_err(dev, "ACP de-init failed\n"); + else + dev_dbg(dev, "ACP de-initialized\n"); + + return 0; +} + +static int snd_acp3x_resume(struct device *dev) +{ + int ret; + struct acp3x_dev_data *adata; + + adata = dev_get_drvdata(dev); + ret = acp3x_init(adata); + if (ret) { + dev_err(dev, "ACP init failed\n"); + return ret; + } + return 0; +} + +static const struct dev_pm_ops acp3x_pm = { + .runtime_suspend = snd_acp3x_suspend, + .runtime_resume = snd_acp3x_resume, + .resume = snd_acp3x_resume, +}; + +static void snd_acp3x_remove(struct pci_dev *pci) +{ + struct acp3x_dev_data *adata; + int i, ret; + + adata = pci_get_drvdata(pci); + if (adata->acp3x_audio_mode == ACP3x_I2S_MODE) { + for (i = 0; i < ACP3x_DEVS; i++) + platform_device_unregister(adata->pdev[i]); + } + ret = acp3x_deinit(adata->acp3x_base); + if (ret) + dev_err(&pci->dev, "ACP de-init failed\n"); + pm_runtime_forbid(&pci->dev); + pm_runtime_get_noresume(&pci->dev); + pci_disable_msi(pci); + pci_release_regions(pci); + pci_disable_device(pci); +} + +static const struct pci_device_id snd_acp3x_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x15e2), + .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, + .class_mask = 0xffffff }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, snd_acp3x_ids); + +static struct pci_driver acp3x_driver = { + .name = KBUILD_MODNAME, + .id_table = snd_acp3x_ids, + .probe = snd_acp3x_probe, + .remove = snd_acp3x_remove, + .driver = { + .pm = &acp3x_pm, + } +}; + +module_pci_driver(acp3x_driver); + +MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com"); +MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); +MODULE_DESCRIPTION("AMD ACP3x PCI driver"); +MODULE_LICENSE("GPL v2"); |