mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-27 00:04:47 +08:00
Merge series "ASoC: Add common modules support for ACP hw block" from Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>:
changes since v3: - rebase and fixes merge conflict. - Fixed kernel autobot warning. Ajit Kumar Pandey (8): ASoC: amd: Add common framework to support I2S on ACP SOC ASoC: amd: acp: Add I2S support on Renoir platform ASoC: amd: acp: Add callback for machine driver on ACP ASoC: amd: acp: Add generic machine driver support for ACP cards ASoC: amd: acp: Add legacy sound card support for Chrome audio ASoC: amd: acp: Add SOF audio support on Chrome board ASoC: amd: acp: Add support for Maxim amplifier codec ASoC: amd: acp: Add support for RT5682-VS codec sound/soc/amd/Kconfig | 2 + sound/soc/amd/Makefile | 1 + sound/soc/amd/acp/Kconfig | 51 +++ sound/soc/amd/acp/Makefile | 26 ++ sound/soc/amd/acp/acp-i2s.c | 340 +++++++++++++++ sound/soc/amd/acp/acp-legacy-mach.c | 104 +++++ sound/soc/amd/acp/acp-mach-common.c | 600 +++++++++++++++++++++++++++ sound/soc/amd/acp/acp-mach.h | 57 +++ sound/soc/amd/acp/acp-platform.c | 315 ++++++++++++++ sound/soc/amd/acp/acp-renoir.c | 144 +++++++ sound/soc/amd/acp/acp-sof-mach.c | 131 ++++++ sound/soc/amd/acp/amd.h | 146 +++++++ sound/soc/amd/acp/chip_offset_byte.h | 76 ++++ 13 files changed, 1993 insertions(+) create mode 100644 sound/soc/amd/acp/Kconfig create mode 100644 sound/soc/amd/acp/Makefile create mode 100644 sound/soc/amd/acp/acp-i2s.c create mode 100644 sound/soc/amd/acp/acp-legacy-mach.c create mode 100644 sound/soc/amd/acp/acp-mach-common.c create mode 100644 sound/soc/amd/acp/acp-mach.h create mode 100644 sound/soc/amd/acp/acp-platform.c create mode 100644 sound/soc/amd/acp/acp-renoir.c create mode 100644 sound/soc/amd/acp/acp-sof-mach.c create mode 100644 sound/soc/amd/acp/amd.h create mode 100644 sound/soc/amd/acp/chip_offset_byte.h -- 2.25.1
This commit is contained in:
commit
e8e8c4a5d1
@ -95,3 +95,5 @@ config SND_SOC_AMD_YC_MACH
|
||||
DMIC can be connected directly to ACP IP.
|
||||
Say m if you have such a device.
|
||||
If unsure select "N".
|
||||
|
||||
source "sound/soc/amd/acp/Kconfig"
|
||||
|
@ -12,3 +12,4 @@ obj-$(CONFIG_SND_SOC_AMD_RV_RT5682_MACH) += snd-soc-acp-rt5682-mach.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/
|
||||
obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/
|
||||
obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/
|
||||
obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/
|
||||
|
51
sound/soc/amd/acp/Kconfig
Normal file
51
sound/soc/amd/acp/Kconfig
Normal file
@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
# This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
# redistributing this file, you may do so under either license.
|
||||
#
|
||||
# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
config SND_SOC_AMD_ACP_COMMON
|
||||
tristate "AMD Audio ACP Common support"
|
||||
select SND_AMD_ACP_CONFIG
|
||||
help
|
||||
This option enables common modules for Audio-Coprocessor i.e. ACP
|
||||
IP block on AMD platforms.
|
||||
|
||||
config SND_SOC_AMD_ACP_I2S
|
||||
tristate
|
||||
|
||||
config SND_SOC_AMD_ACP_PCM
|
||||
tristate
|
||||
|
||||
config SND_AMD_ASOC_RENOIR
|
||||
tristate "AMD ACP ASOC Renoir Support"
|
||||
select SND_SOC_AMD_ACP_PCM
|
||||
select SND_SOC_AMD_ACP_I2S
|
||||
depends on X86 && PCI
|
||||
help
|
||||
This option enables Renoir I2S support on AMD platform.
|
||||
|
||||
config SND_SOC_AMD_MACH_COMMON
|
||||
tristate
|
||||
select CLK_FIXED_FCH
|
||||
select SND_SOC_RT5682_I2C
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_RT1019
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_RT5682S
|
||||
depends on X86 && PCI && I2C
|
||||
help
|
||||
This option enables common Machine driver module for ACP.
|
||||
|
||||
config SND_SOC_AMD_LEGACY_MACH
|
||||
tristate "AMD Legacy Machine Driver Support"
|
||||
select SND_SOC_AMD_MACH_COMMON
|
||||
help
|
||||
This option enables legacy sound card support for ACP audio.
|
||||
|
||||
config SND_SOC_AMD_SOF_MACH
|
||||
tristate "AMD SOF Machine Driver Support"
|
||||
select SND_SOC_AMD_MACH_COMMON
|
||||
help
|
||||
This option enables SOF sound card support for ACP audio.
|
26
sound/soc/amd/acp/Makefile
Normal file
26
sound/soc/amd/acp/Makefile
Normal file
@ -0,0 +1,26 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
# This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
# redistributing this file, you may do so under either license.
|
||||
#
|
||||
# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
#common acp driver
|
||||
snd-acp-pcm-objs := acp-platform.o
|
||||
snd-acp-i2s-objs := acp-i2s.o
|
||||
|
||||
#platform specific driver
|
||||
snd-acp-renoir-objs := acp-renoir.o
|
||||
|
||||
#machine specific driver
|
||||
snd-acp-mach-objs := acp-mach-common.o
|
||||
snd-acp-legacy-mach-objs := acp-legacy-mach.o
|
||||
snd-acp-sof-mach-objs := acp-sof-mach.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o
|
||||
|
||||
obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o
|
||||
obj-$(CONFIG_SND_SOC_AMD_SOF_MACH) += snd-acp-sof-mach.o
|
340
sound/soc/amd/acp/acp-i2s.c
Normal file
340
sound/soc/amd/acp/acp-i2s.c
Normal file
@ -0,0 +1,340 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
//
|
||||
// This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
// redistributing this file, you may do so under either license.
|
||||
//
|
||||
// Copyright(c) 2021 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
||||
//
|
||||
|
||||
/*
|
||||
* Generic Hardware interface for ACP Audio I2S controller
|
||||
*/
|
||||
|
||||
#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 "amd.h"
|
||||
|
||||
#define DRV_NAME "acp_i2s_playcap"
|
||||
|
||||
static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct device *dev = dai->component->dev;
|
||||
struct acp_dev_data *adata;
|
||||
u32 val;
|
||||
u32 xfer_resolution;
|
||||
u32 reg_val;
|
||||
|
||||
adata = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
/* These values are as per Hardware Spec */
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_U8:
|
||||
case SNDRV_PCM_FORMAT_S8:
|
||||
xfer_resolution = 0x0;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
xfer_resolution = 0x02;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
xfer_resolution = 0x04;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
xfer_resolution = 0x05;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
switch (dai->driver->id) {
|
||||
case I2S_BT_INSTANCE:
|
||||
reg_val = ACP_BTTDM_ITER;
|
||||
break;
|
||||
case I2S_SP_INSTANCE:
|
||||
reg_val = ACP_I2STDM_ITER;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
switch (dai->driver->id) {
|
||||
case I2S_BT_INSTANCE:
|
||||
reg_val = ACP_BTTDM_IRER;
|
||||
break;
|
||||
case I2S_SP_INSTANCE:
|
||||
reg_val = ACP_I2STDM_IRER;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
val = readl(adata->acp_base + reg_val);
|
||||
val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;
|
||||
val = val | (xfer_resolution << 3);
|
||||
writel(val, adata->acp_base + reg_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct acp_stream *stream = substream->runtime->private_data;
|
||||
struct device *dev = dai->component->dev;
|
||||
struct acp_dev_data *adata = dev_get_drvdata(dev);
|
||||
u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;
|
||||
|
||||
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:
|
||||
stream->bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
switch (dai->driver->id) {
|
||||
case I2S_BT_INSTANCE:
|
||||
water_val = ACP_BT_TX_INTR_WATERMARK_SIZE;
|
||||
reg_val = ACP_BTTDM_ITER;
|
||||
ier_val = ACP_BTTDM_IER;
|
||||
buf_reg = ACP_BT_TX_RINGBUFSIZE;
|
||||
break;
|
||||
case I2S_SP_INSTANCE:
|
||||
water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE;
|
||||
reg_val = ACP_I2STDM_ITER;
|
||||
ier_val = ACP_I2STDM_IER;
|
||||
buf_reg = ACP_I2S_TX_RINGBUFSIZE;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
switch (dai->driver->id) {
|
||||
case I2S_BT_INSTANCE:
|
||||
water_val = ACP_BT_RX_INTR_WATERMARK_SIZE;
|
||||
reg_val = ACP_BTTDM_IRER;
|
||||
ier_val = ACP_BTTDM_IER;
|
||||
buf_reg = ACP_BT_RX_RINGBUFSIZE;
|
||||
break;
|
||||
case I2S_SP_INSTANCE:
|
||||
water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE;
|
||||
reg_val = ACP_I2STDM_IRER;
|
||||
ier_val = ACP_I2STDM_IER;
|
||||
buf_reg = ACP_I2S_RX_RINGBUFSIZE;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
writel(period_bytes, adata->acp_base + water_val);
|
||||
writel(buf_size, adata->acp_base + buf_reg);
|
||||
val = readl(adata->acp_base + reg_val);
|
||||
val = val | BIT(0);
|
||||
writel(val, adata->acp_base + reg_val);
|
||||
writel(1, adata->acp_base + ier_val);
|
||||
return 0;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
switch (dai->driver->id) {
|
||||
case I2S_BT_INSTANCE:
|
||||
reg_val = ACP_BTTDM_ITER;
|
||||
break;
|
||||
case I2S_SP_INSTANCE:
|
||||
reg_val = ACP_I2STDM_ITER;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
} else {
|
||||
switch (dai->driver->id) {
|
||||
case I2S_BT_INSTANCE:
|
||||
reg_val = ACP_BTTDM_IRER;
|
||||
break;
|
||||
case I2S_SP_INSTANCE:
|
||||
reg_val = ACP_I2STDM_IRER;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
val = readl(adata->acp_base + reg_val);
|
||||
val = val & ~BIT(0);
|
||||
writel(val, adata->acp_base + reg_val);
|
||||
|
||||
if (!(readl(adata->acp_base + ACP_BTTDM_ITER) & BIT(0)) &&
|
||||
!(readl(adata->acp_base + ACP_BTTDM_IRER) & BIT(0)))
|
||||
writel(0, adata->acp_base + ACP_BTTDM_IER);
|
||||
if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) &&
|
||||
!(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0)))
|
||||
writel(0, adata->acp_base + ACP_I2STDM_IER);
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct device *dev = dai->component->dev;
|
||||
struct acp_dev_data *adata = dev_get_drvdata(dev);
|
||||
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;
|
||||
|
||||
switch (dai->driver->id) {
|
||||
case I2S_SP_INSTANCE:
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
reg_dma_size = ACP_I2S_TX_DMA_SIZE;
|
||||
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
|
||||
SP_PB_FIFO_ADDR_OFFSET;
|
||||
reg_fifo_addr = ACP_I2S_TX_FIFOADDR;
|
||||
reg_fifo_size = ACP_I2S_TX_FIFOSIZE;
|
||||
|
||||
phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
|
||||
writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR);
|
||||
} else {
|
||||
reg_dma_size = ACP_I2S_RX_DMA_SIZE;
|
||||
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
|
||||
SP_CAPT_FIFO_ADDR_OFFSET;
|
||||
reg_fifo_addr = ACP_I2S_RX_FIFOADDR;
|
||||
reg_fifo_size = ACP_I2S_RX_FIFOSIZE;
|
||||
phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
|
||||
writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR);
|
||||
}
|
||||
break;
|
||||
case I2S_BT_INSTANCE:
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
reg_dma_size = ACP_BT_TX_DMA_SIZE;
|
||||
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
|
||||
BT_PB_FIFO_ADDR_OFFSET;
|
||||
reg_fifo_addr = ACP_BT_TX_FIFOADDR;
|
||||
reg_fifo_size = ACP_BT_TX_FIFOSIZE;
|
||||
|
||||
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
|
||||
writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR);
|
||||
} else {
|
||||
reg_dma_size = ACP_BT_RX_DMA_SIZE;
|
||||
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
|
||||
BT_CAPT_FIFO_ADDR_OFFSET;
|
||||
reg_fifo_addr = ACP_BT_RX_FIFOADDR;
|
||||
reg_fifo_size = ACP_BT_RX_FIFOSIZE;
|
||||
|
||||
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
|
||||
writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
writel(DMA_SIZE, adata->acp_base + reg_dma_size);
|
||||
writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);
|
||||
writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);
|
||||
|
||||
ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
|
||||
ext_int_ctrl |= BIT(I2S_RX_THRESHOLD) | BIT(BT_RX_THRESHOLD)
|
||||
| BIT(I2S_TX_THRESHOLD) | BIT(BT_TX_THRESHOLD);
|
||||
|
||||
writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct acp_stream *stream = substream->runtime->private_data;
|
||||
struct device *dev = dai->component->dev;
|
||||
unsigned int dir = substream->stream;
|
||||
unsigned int irq_bit = 0;
|
||||
|
||||
switch (dai->driver->id) {
|
||||
case I2S_SP_INSTANCE:
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
irq_bit = BIT(I2S_TX_THRESHOLD);
|
||||
stream->pte_offset = ACP_SRAM_SP_PB_PTE_OFFSET;
|
||||
stream->fifo_offset = SP_PB_FIFO_ADDR_OFFSET;
|
||||
} else {
|
||||
irq_bit = BIT(I2S_RX_THRESHOLD);
|
||||
stream->pte_offset = ACP_SRAM_SP_CP_PTE_OFFSET;
|
||||
stream->fifo_offset = SP_CAPT_FIFO_ADDR_OFFSET;
|
||||
}
|
||||
break;
|
||||
case I2S_BT_INSTANCE:
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
irq_bit = BIT(BT_TX_THRESHOLD);
|
||||
stream->pte_offset = ACP_SRAM_BT_PB_PTE_OFFSET;
|
||||
stream->fifo_offset = BT_PB_FIFO_ADDR_OFFSET;
|
||||
} else {
|
||||
irq_bit = BIT(BT_RX_THRESHOLD);
|
||||
stream->pte_offset = ACP_SRAM_BT_CP_PTE_OFFSET;
|
||||
stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Save runtime dai configuration in stream */
|
||||
stream->id = dai->driver->id + dir;
|
||||
stream->dai_id = dai->driver->id;
|
||||
stream->irq_bit = irq_bit;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
|
||||
.startup = acp_i2s_startup,
|
||||
.hw_params = acp_i2s_hwparams,
|
||||
.prepare = acp_i2s_prepare,
|
||||
.trigger = acp_i2s_trigger,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
|
||||
|
||||
int asoc_acp_i2s_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct device *dev = dai->component->dev;
|
||||
struct acp_dev_data *adata = dev_get_drvdata(dev);
|
||||
unsigned int val;
|
||||
|
||||
if (!adata->acp_base) {
|
||||
dev_err(dev, "I2S base is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val = readl(adata->acp_base + ACP_I2S_PIN_CONFIG);
|
||||
if (val != I2S_MODE) {
|
||||
dev_err(dev, "I2S Mode not supported val %x\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(asoc_acp_i2s_probe, SND_SOC_ACP_COMMON);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_ALIAS(DRV_NAME);
|
104
sound/soc/amd/acp/acp-legacy-mach.c
Normal file
104
sound/soc/amd/acp/acp-legacy-mach.c
Normal file
@ -0,0 +1,104 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
//
|
||||
// This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
// redistributing this file, you may do so under either license.
|
||||
//
|
||||
// Copyright(c) 2021 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
||||
//
|
||||
|
||||
/*
|
||||
* Machine Driver Legacy Support for ACP HW block
|
||||
*/
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "acp-mach.h"
|
||||
|
||||
static struct acp_card_drvdata rt5682_rt1019_data = {
|
||||
.hs_cpu_id = I2S_SP,
|
||||
.amp_cpu_id = I2S_SP,
|
||||
.dmic_cpu_id = NONE,
|
||||
.hs_codec_id = RT5682,
|
||||
.amp_codec_id = RT1019,
|
||||
.dmic_codec_id = NONE,
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new acp_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Spk"),
|
||||
SOC_DAPM_PIN_SWITCH("Left Spk"),
|
||||
SOC_DAPM_PIN_SWITCH("Right Spk"),
|
||||
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget acp_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Spk", NULL),
|
||||
SND_SOC_DAPM_SPK("Left Spk", NULL),
|
||||
SND_SOC_DAPM_SPK("Right Spk", NULL),
|
||||
};
|
||||
|
||||
static int acp_asoc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = NULL;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
if (!pdev->id_entry)
|
||||
return -EINVAL;
|
||||
|
||||
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
|
||||
if (!card)
|
||||
return -ENOMEM;
|
||||
|
||||
card->dev = dev;
|
||||
card->owner = THIS_MODULE;
|
||||
card->name = pdev->id_entry->name;
|
||||
card->dapm_widgets = acp_widgets;
|
||||
card->num_dapm_widgets = ARRAY_SIZE(acp_widgets);
|
||||
card->controls = acp_controls;
|
||||
card->num_controls = ARRAY_SIZE(acp_controls);
|
||||
card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
|
||||
|
||||
acp_legacy_dai_links_create(card);
|
||||
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"devm_snd_soc_register_card(%s) failed: %d\n",
|
||||
card->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id board_ids[] = {
|
||||
{
|
||||
.name = "rn_rt5682_rt1019",
|
||||
.driver_data = (kernel_ulong_t)&rt5682_rt1019_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
static struct platform_driver acp_asoc_audio = {
|
||||
.driver = {
|
||||
.name = "acp_mach",
|
||||
},
|
||||
.probe = acp_asoc_probe,
|
||||
.id_table = board_ids,
|
||||
};
|
||||
|
||||
module_platform_driver(acp_asoc_audio);
|
||||
|
||||
MODULE_IMPORT_NS(SND_SOC_AMD_MACH);
|
||||
MODULE_DESCRIPTION("ACP chrome audio support");
|
||||
MODULE_ALIAS("platform:rn_rt5682_rt1019");
|
||||
MODULE_LICENSE("GPL v2");
|
600
sound/soc/amd/acp/acp-mach-common.c
Normal file
600
sound/soc/amd/acp/acp-mach-common.c
Normal file
@ -0,0 +1,600 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
//
|
||||
// This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
// redistributing this file, you may do so under either license.
|
||||
//
|
||||
// Copyright(c) 2021 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
||||
// Vijendar Mukunda <Vijendar.Mukunda@amd.com>
|
||||
//
|
||||
|
||||
/*
|
||||
* Machine Driver Interface for ACP HW block
|
||||
*/
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "../../codecs/rt5682.h"
|
||||
#include "../../codecs/rt1019.h"
|
||||
#include "../../codecs/rt5682s.h"
|
||||
#include "acp-mach.h"
|
||||
|
||||
#define PCO_PLAT_CLK 48000000
|
||||
#define RT5682_PLL_FREQ (48000 * 512)
|
||||
#define DUAL_CHANNEL 2
|
||||
#define FOUR_CHANNEL 4
|
||||
|
||||
static struct snd_soc_jack pco_jack;
|
||||
|
||||
static const unsigned int channels[] = {
|
||||
DUAL_CHANNEL,
|
||||
};
|
||||
|
||||
static const unsigned int rates[] = {
|
||||
48000,
|
||||
};
|
||||
|
||||
static const struct snd_pcm_hw_constraint_list constraints_rates = {
|
||||
.count = ARRAY_SIZE(rates),
|
||||
.list = rates,
|
||||
.mask = 0,
|
||||
};
|
||||
|
||||
static const struct snd_pcm_hw_constraint_list constraints_channels = {
|
||||
.count = ARRAY_SIZE(channels),
|
||||
.list = channels,
|
||||
.mask = 0,
|
||||
};
|
||||
|
||||
static int acp_clk_enable(struct acp_card_drvdata *drvdata)
|
||||
{
|
||||
clk_set_rate(drvdata->wclk, 48000);
|
||||
clk_set_rate(drvdata->bclk, 48000 * 64);
|
||||
|
||||
return clk_prepare_enable(drvdata->wclk);
|
||||
}
|
||||
|
||||
/* Declare RT5682 codec components */
|
||||
SND_SOC_DAILINK_DEF(rt5682,
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1")));
|
||||
|
||||
static const struct snd_soc_dapm_route rt5682_map[] = {
|
||||
{ "Headphone Jack", NULL, "HPOL" },
|
||||
{ "Headphone Jack", NULL, "HPOR" },
|
||||
{ "IN1P", NULL, "Headset Mic" },
|
||||
};
|
||||
|
||||
/* Define card ops for RT5682 CODEC */
|
||||
static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_card_drvdata *drvdata = card->drvdata;
|
||||
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
int ret;
|
||||
|
||||
dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
|
||||
|
||||
if (drvdata->hs_codec_id != RT5682)
|
||||
return -EINVAL;
|
||||
|
||||
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK,
|
||||
PCO_PLAT_CLK, RT5682_PLL_FREQ);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2,
|
||||
RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set tdm/i2s1 master bclk ratio */
|
||||
ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "Failed to set rt5682 tdm bclk ratio: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
|
||||
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
|
||||
|
||||
ret = snd_soc_card_jack_new(card, "Headset Jack",
|
||||
SND_JACK_HEADSET | SND_JACK_LINEOUT |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3,
|
||||
&pco_jack, NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(card->dev, "HP jack creation failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
|
||||
|
||||
ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682_map, ARRAY_SIZE(rt5682_map));
|
||||
}
|
||||
|
||||
static int acp_card_hs_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_card_drvdata *drvdata = card->drvdata;
|
||||
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
ret = acp_clk_enable(drvdata);
|
||||
if (ret < 0)
|
||||
dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void acp_card_shutdown(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_card_drvdata *drvdata = card->drvdata;
|
||||
|
||||
clk_disable_unprepare(drvdata->wclk);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops acp_card_rt5682_ops = {
|
||||
.startup = acp_card_hs_startup,
|
||||
.shutdown = acp_card_shutdown,
|
||||
};
|
||||
|
||||
/* Define RT5682S CODEC component*/
|
||||
SND_SOC_DAILINK_DEF(rt5682s,
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1")));
|
||||
|
||||
static const struct snd_soc_dapm_route rt5682s_map[] = {
|
||||
{ "Headphone Jack", NULL, "HPOL" },
|
||||
{ "Headphone Jack", NULL, "HPOR" },
|
||||
{ "IN1P", NULL, "Headset Mic" },
|
||||
};
|
||||
|
||||
static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_card_drvdata *drvdata = card->drvdata;
|
||||
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
|
||||
struct snd_soc_component *component = codec_dai->component;
|
||||
int ret;
|
||||
|
||||
dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
|
||||
|
||||
if (drvdata->hs_codec_id != RT5682S)
|
||||
return -EINVAL;
|
||||
|
||||
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBP_CFP);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL2, RT5682S_PLL_S_MCLK,
|
||||
PCO_PLAT_CLK, RT5682_PLL_FREQ);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL2,
|
||||
RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set tdm/i2s1 master bclk ratio */
|
||||
ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "Failed to set rt5682 tdm bclk ratio: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
|
||||
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
|
||||
|
||||
ret = snd_soc_card_jack_new(card, "Headset Jack",
|
||||
SND_JACK_HEADSET | SND_JACK_LINEOUT |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3,
|
||||
&pco_jack, NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(card->dev, "HP jack creation failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
|
||||
|
||||
ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
|
||||
if (ret) {
|
||||
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682s_map, ARRAY_SIZE(rt5682s_map));
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops acp_card_rt5682s_ops = {
|
||||
.startup = acp_card_hs_startup,
|
||||
.shutdown = acp_card_shutdown,
|
||||
};
|
||||
|
||||
/* Declare RT1019 codec components */
|
||||
SND_SOC_DAILINK_DEF(rt1019,
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:01", "rt1019-aif"),
|
||||
COMP_CODEC("i2c-10EC1019:02", "rt1019-aif")));
|
||||
|
||||
static const struct snd_soc_dapm_route rt1019_map_lr[] = {
|
||||
{ "Left Spk", NULL, "Left SPO" },
|
||||
{ "Right Spk", NULL, "Right SPO" },
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_conf rt1019_conf[] = {
|
||||
{
|
||||
.dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
|
||||
.name_prefix = "Left",
|
||||
},
|
||||
{
|
||||
.dlc = COMP_CODEC_CONF("i2c-10EC1019:02"),
|
||||
.name_prefix = "Right",
|
||||
},
|
||||
};
|
||||
|
||||
static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_card_drvdata *drvdata = card->drvdata;
|
||||
|
||||
if (drvdata->amp_codec_id != RT1019)
|
||||
return -EINVAL;
|
||||
|
||||
return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr,
|
||||
ARRAY_SIZE(rt1019_map_lr));
|
||||
}
|
||||
|
||||
static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_card_drvdata *drvdata = card->drvdata;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
int srate, i, ret = 0;
|
||||
|
||||
srate = params_rate(params);
|
||||
|
||||
if (drvdata->amp_codec_id != RT1019)
|
||||
return -EINVAL;
|
||||
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
if (strcmp(codec_dai->name, "rt1019-aif"))
|
||||
continue;
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0, RT1019_PLL_S_BCLK,
|
||||
64 * srate, 256 * srate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT1019_SCLK_S_PLL,
|
||||
256 * srate, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acp_card_amp_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_card_drvdata *drvdata = card->drvdata;
|
||||
int ret;
|
||||
|
||||
runtime->hw.channels_max = DUAL_CHANNEL;
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
&constraints_channels);
|
||||
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_rates);
|
||||
|
||||
ret = acp_clk_enable(drvdata);
|
||||
if (ret < 0)
|
||||
dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops acp_card_rt1019_ops = {
|
||||
.startup = acp_card_amp_startup,
|
||||
.shutdown = acp_card_shutdown,
|
||||
.hw_params = acp_card_rt1019_hw_params,
|
||||
};
|
||||
|
||||
/* Declare Maxim codec components */
|
||||
SND_SOC_DAILINK_DEF(max98360a,
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi")));
|
||||
|
||||
static const struct snd_soc_dapm_route max98360a_map[] = {
|
||||
{"Spk", NULL, "Speaker"},
|
||||
};
|
||||
|
||||
static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct acp_card_drvdata *drvdata = card->drvdata;
|
||||
|
||||
if (drvdata->amp_codec_id != MAX98360A)
|
||||
return -EINVAL;
|
||||
|
||||
return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map,
|
||||
ARRAY_SIZE(max98360a_map));
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops acp_card_maxim_ops = {
|
||||
.startup = acp_card_amp_startup,
|
||||
.shutdown = acp_card_shutdown,
|
||||
};
|
||||
|
||||
/* Declare DMIC codec components */
|
||||
SND_SOC_DAILINK_DEF(dmic_codec,
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
|
||||
|
||||
/* Declare ACP CPU components */
|
||||
static struct snd_soc_dai_link_component dummy_codec[] = {
|
||||
{
|
||||
.name = "snd-soc-dummy",
|
||||
.dai_name = "snd-soc-dummy-dai",
|
||||
}
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link_component platform_component[] = {
|
||||
{
|
||||
.name = "acp_asoc_renoir.0",
|
||||
}
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link_component sof_component[] = {
|
||||
{
|
||||
.name = "0000:04:00.5",
|
||||
}
|
||||
};
|
||||
|
||||
SND_SOC_DAILINK_DEF(i2s_sp,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp")));
|
||||
SND_SOC_DAILINK_DEF(sof_sp,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp")));
|
||||
SND_SOC_DAILINK_DEF(sof_dmic,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic")));
|
||||
|
||||
int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_dai_link *links;
|
||||
struct device *dev = card->dev;
|
||||
struct acp_card_drvdata *drv_data = card->drvdata;
|
||||
int i = 0, num_links = 0;
|
||||
|
||||
if (drv_data->hs_cpu_id)
|
||||
num_links++;
|
||||
if (drv_data->amp_cpu_id)
|
||||
num_links++;
|
||||
if (drv_data->dmic_cpu_id)
|
||||
num_links++;
|
||||
|
||||
links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
|
||||
if (!links)
|
||||
return -ENOMEM;
|
||||
|
||||
if (drv_data->hs_cpu_id == I2S_SP) {
|
||||
links[i].name = "acp-headset-codec";
|
||||
links[i].id = HEADSET_BE_ID;
|
||||
links[i].cpus = sof_sp;
|
||||
links[i].num_cpus = ARRAY_SIZE(sof_sp);
|
||||
links[i].platforms = sof_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(sof_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].dpcm_capture = 1;
|
||||
links[i].nonatomic = true;
|
||||
links[i].no_pcm = 1;
|
||||
if (!drv_data->hs_codec_id) {
|
||||
/* Use dummy codec if codec id not specified */
|
||||
links[i].codecs = dummy_codec;
|
||||
links[i].num_codecs = ARRAY_SIZE(dummy_codec);
|
||||
}
|
||||
if (drv_data->hs_codec_id == RT5682) {
|
||||
links[i].codecs = rt5682;
|
||||
links[i].num_codecs = ARRAY_SIZE(rt5682);
|
||||
links[i].init = acp_card_rt5682_init;
|
||||
links[i].ops = &acp_card_rt5682_ops;
|
||||
}
|
||||
if (drv_data->hs_codec_id == RT5682S) {
|
||||
links[i].codecs = rt5682s;
|
||||
links[i].num_codecs = ARRAY_SIZE(rt5682s);
|
||||
links[i].init = acp_card_rt5682s_init;
|
||||
links[i].ops = &acp_card_rt5682s_ops;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (drv_data->amp_cpu_id == I2S_SP) {
|
||||
links[i].name = "acp-amp-codec";
|
||||
links[i].id = AMP_BE_ID;
|
||||
links[i].cpus = sof_sp;
|
||||
links[i].num_cpus = ARRAY_SIZE(sof_sp);
|
||||
links[i].platforms = sof_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(sof_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].nonatomic = true;
|
||||
links[i].no_pcm = 1;
|
||||
if (!drv_data->amp_codec_id) {
|
||||
/* Use dummy codec if codec id not specified */
|
||||
links[i].codecs = dummy_codec;
|
||||
links[i].num_codecs = ARRAY_SIZE(dummy_codec);
|
||||
}
|
||||
if (drv_data->amp_codec_id == RT1019) {
|
||||
links[i].codecs = rt1019;
|
||||
links[i].num_codecs = ARRAY_SIZE(rt1019);
|
||||
links[i].ops = &acp_card_rt1019_ops;
|
||||
links[i].init = acp_card_rt1019_init;
|
||||
card->codec_conf = rt1019_conf;
|
||||
card->num_configs = ARRAY_SIZE(rt1019_conf);
|
||||
}
|
||||
if (drv_data->amp_codec_id == MAX98360A) {
|
||||
links[i].codecs = max98360a;
|
||||
links[i].num_codecs = ARRAY_SIZE(max98360a);
|
||||
links[i].ops = &acp_card_maxim_ops;
|
||||
links[i].init = acp_card_maxim_init;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (drv_data->dmic_cpu_id == DMIC) {
|
||||
links[i].name = "acp-dmic-codec";
|
||||
links[i].id = DMIC_BE_ID;
|
||||
links[i].codecs = dmic_codec;
|
||||
links[i].num_codecs = ARRAY_SIZE(dmic_codec);
|
||||
links[i].cpus = sof_dmic;
|
||||
links[i].num_cpus = ARRAY_SIZE(sof_dmic);
|
||||
links[i].platforms = sof_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(sof_component);
|
||||
links[i].dpcm_capture = 1;
|
||||
links[i].nonatomic = true;
|
||||
links[i].no_pcm = 1;
|
||||
}
|
||||
|
||||
card->dai_link = links;
|
||||
card->num_links = num_links;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(acp_sofdsp_dai_links_create, SND_SOC_AMD_MACH);
|
||||
|
||||
int acp_legacy_dai_links_create(struct snd_soc_card *card)
|
||||
{
|
||||
struct snd_soc_dai_link *links;
|
||||
struct device *dev = card->dev;
|
||||
struct acp_card_drvdata *drv_data = card->drvdata;
|
||||
int i = 0, num_links = 0;
|
||||
|
||||
if (drv_data->hs_cpu_id)
|
||||
num_links++;
|
||||
if (drv_data->amp_cpu_id)
|
||||
num_links++;
|
||||
if (drv_data->dmic_cpu_id)
|
||||
num_links++;
|
||||
|
||||
links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
|
||||
|
||||
if (drv_data->hs_cpu_id == I2S_SP) {
|
||||
links[i].name = "acp-headset-codec";
|
||||
links[i].id = HEADSET_BE_ID;
|
||||
links[i].cpus = i2s_sp;
|
||||
links[i].num_cpus = ARRAY_SIZE(i2s_sp);
|
||||
links[i].platforms = platform_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
links[i].dpcm_capture = 1;
|
||||
if (!drv_data->hs_codec_id) {
|
||||
/* Use dummy codec if codec id not specified */
|
||||
links[i].codecs = dummy_codec;
|
||||
links[i].num_codecs = ARRAY_SIZE(dummy_codec);
|
||||
}
|
||||
if (drv_data->hs_codec_id == RT5682) {
|
||||
links[i].codecs = rt5682;
|
||||
links[i].num_codecs = ARRAY_SIZE(rt5682);
|
||||
links[i].init = acp_card_rt5682_init;
|
||||
links[i].ops = &acp_card_rt5682_ops;
|
||||
}
|
||||
if (drv_data->hs_codec_id == RT5682S) {
|
||||
links[i].codecs = rt5682s;
|
||||
links[i].num_codecs = ARRAY_SIZE(rt5682s);
|
||||
links[i].init = acp_card_rt5682s_init;
|
||||
links[i].ops = &acp_card_rt5682s_ops;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (drv_data->amp_cpu_id == I2S_SP) {
|
||||
links[i].name = "acp-amp-codec";
|
||||
links[i].id = AMP_BE_ID;
|
||||
links[i].cpus = i2s_sp;
|
||||
links[i].num_cpus = ARRAY_SIZE(i2s_sp);
|
||||
links[i].platforms = platform_component;
|
||||
links[i].num_platforms = ARRAY_SIZE(platform_component);
|
||||
links[i].dpcm_playback = 1;
|
||||
if (!drv_data->amp_codec_id) {
|
||||
/* Use dummy codec if codec id not specified */
|
||||
links[i].codecs = dummy_codec;
|
||||
links[i].num_codecs = ARRAY_SIZE(dummy_codec);
|
||||
}
|
||||
if (drv_data->amp_codec_id == RT1019) {
|
||||
links[i].codecs = rt1019;
|
||||
links[i].num_codecs = ARRAY_SIZE(rt1019);
|
||||
links[i].ops = &acp_card_rt1019_ops;
|
||||
links[i].init = acp_card_rt1019_init;
|
||||
card->codec_conf = rt1019_conf;
|
||||
card->num_configs = ARRAY_SIZE(rt1019_conf);
|
||||
}
|
||||
if (drv_data->amp_codec_id == MAX98360A) {
|
||||
links[i].codecs = max98360a;
|
||||
links[i].num_codecs = ARRAY_SIZE(max98360a);
|
||||
links[i].ops = &acp_card_maxim_ops;
|
||||
links[i].init = acp_card_maxim_init;
|
||||
}
|
||||
}
|
||||
|
||||
card->dai_link = links;
|
||||
card->num_links = num_links;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(acp_legacy_dai_links_create, SND_SOC_AMD_MACH);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
57
sound/soc/amd/acp/acp-mach.h
Normal file
57
sound/soc/amd/acp/acp-mach.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
*
|
||||
* Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
||||
*/
|
||||
#ifndef __ACP_MACH_H
|
||||
#define __ACP_MACH_H
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
enum be_id {
|
||||
HEADSET_BE_ID = 0,
|
||||
AMP_BE_ID,
|
||||
DMIC_BE_ID,
|
||||
};
|
||||
|
||||
enum cpu_endpoints {
|
||||
NONE = 0,
|
||||
I2S_SP,
|
||||
I2S_BT,
|
||||
DMIC,
|
||||
};
|
||||
|
||||
enum codec_endpoints {
|
||||
DUMMY = 0,
|
||||
RT5682,
|
||||
RT1019,
|
||||
MAX98360A,
|
||||
RT5682S,
|
||||
};
|
||||
|
||||
struct acp_card_drvdata {
|
||||
unsigned int hs_cpu_id;
|
||||
unsigned int amp_cpu_id;
|
||||
unsigned int dmic_cpu_id;
|
||||
unsigned int hs_codec_id;
|
||||
unsigned int amp_codec_id;
|
||||
unsigned int dmic_codec_id;
|
||||
unsigned int dai_fmt;
|
||||
struct clk *wclk;
|
||||
struct clk *bclk;
|
||||
};
|
||||
|
||||
int acp_sofdsp_dai_links_create(struct snd_soc_card *card);
|
||||
int acp_legacy_dai_links_create(struct snd_soc_card *card);
|
||||
|
||||
#endif
|
315
sound/soc/amd/acp/acp-platform.c
Normal file
315
sound/soc/amd/acp/acp-platform.c
Normal file
@ -0,0 +1,315 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
//
|
||||
// This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
// redistributing this file, you may do so under either license.
|
||||
//
|
||||
// Copyright(c) 2021 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
||||
|
||||
/*
|
||||
* Generic interface for ACP audio blck PCM component
|
||||
*/
|
||||
|
||||
#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/pm_runtime.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "amd.h"
|
||||
|
||||
#define DRV_NAME "acp_i2s_dma"
|
||||
|
||||
static const struct snd_pcm_hardware acp_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 acp_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,
|
||||
};
|
||||
|
||||
int acp_machine_select(struct acp_dev_data *adata)
|
||||
{
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
int size;
|
||||
|
||||
size = sizeof(*adata->machines);
|
||||
mach = snd_soc_acpi_find_machine(adata->machines);
|
||||
if (!mach) {
|
||||
dev_err(adata->dev, "warning: No matching ASoC machine driver found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adata->mach_dev = platform_device_register_data(adata->dev, mach->drv_name,
|
||||
PLATFORM_DEVID_NONE, mach, size);
|
||||
if (!adata->mach_dev)
|
||||
dev_warn(adata->dev, "Unable to register Machine device\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(acp_machine_select, SND_SOC_ACP_COMMON);
|
||||
|
||||
static irqreturn_t i2s_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct acp_dev_data *adata = data;
|
||||
struct acp_stream *stream;
|
||||
u16 i2s_flag = 0;
|
||||
u32 val, i;
|
||||
|
||||
if (!adata)
|
||||
return IRQ_NONE;
|
||||
|
||||
val = readl(adata->acp_base + ACP_EXTERNAL_INTR_STAT);
|
||||
|
||||
for (i = 0; i < ACP_MAX_STREAM; i++) {
|
||||
stream = adata->stream[i];
|
||||
if (stream && (val & stream->irq_bit)) {
|
||||
writel(stream->irq_bit, adata->acp_base + ACP_EXTERNAL_INTR_STAT);
|
||||
snd_pcm_period_elapsed(stream->substream);
|
||||
i2s_flag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i2s_flag)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream)
|
||||
{
|
||||
u32 pte_reg, pte_size, reg_val;
|
||||
|
||||
/* Use ATU base Group5 */
|
||||
pte_reg = ACPAXI2AXI_ATU_BASE_ADDR_GRP_5;
|
||||
pte_size = ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5;
|
||||
stream->reg_offset = 0x02000000;
|
||||
|
||||
/* Group Enable */
|
||||
reg_val = ACP_SRAM_PTE_OFFSET;
|
||||
writel(reg_val | BIT(31), adata->acp_base + pte_reg);
|
||||
writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + pte_size);
|
||||
}
|
||||
|
||||
static void config_acp_dma(struct acp_dev_data *adata, int cpu_id, int size)
|
||||
{
|
||||
struct acp_stream *stream = adata->stream[cpu_id];
|
||||
struct snd_pcm_substream *substream = stream->substream;
|
||||
dma_addr_t addr = substream->dma_buffer.addr;
|
||||
int num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
|
||||
u32 low, high, val;
|
||||
u16 page_idx;
|
||||
|
||||
val = stream->pte_offset;
|
||||
|
||||
for (page_idx = 0; page_idx < 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);
|
||||
writel(low, adata->acp_base + ACP_SCRATCH_REG_0 + val);
|
||||
high |= BIT(31);
|
||||
writel(high, adata->acp_base + ACP_SCRATCH_REG_0 + val + 4);
|
||||
|
||||
/* Move to next physically contiguous page */
|
||||
val += 8;
|
||||
addr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct device *dev = component->dev;
|
||||
struct acp_dev_data *adata = dev_get_drvdata(dev);
|
||||
struct acp_stream *stream;
|
||||
int stream_id = cpu_dai->driver->id * 2 + substream->stream;
|
||||
int ret;
|
||||
|
||||
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
|
||||
if (!stream)
|
||||
return -ENOMEM;
|
||||
|
||||
stream->substream = substream;
|
||||
adata->stream[stream_id] = stream;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
runtime->hw = acp_pcm_hardware_playback;
|
||||
else
|
||||
runtime->hw = acp_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(stream);
|
||||
return ret;
|
||||
}
|
||||
runtime->private_data = stream;
|
||||
|
||||
writel(1, adata->acp_base + ACP_EXTERNAL_INTR_ENB);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acp_dma_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
|
||||
struct acp_dev_data *adata = snd_soc_component_get_drvdata(component);
|
||||
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
|
||||
struct acp_stream *stream = substream->runtime->private_data;
|
||||
int stream_id = cpu_dai->driver->id * 2 + substream->stream;
|
||||
u64 size = params_buffer_bytes(params);
|
||||
|
||||
/* Configure ACP DMA block with params */
|
||||
config_pte_for_stream(adata, stream);
|
||||
config_acp_dma(adata, stream_id, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct device *dev = component->dev;
|
||||
struct acp_dev_data *adata = dev_get_drvdata(dev);
|
||||
struct acp_stream *stream = substream->runtime->private_data;
|
||||
u32 pos, buffersize;
|
||||
u64 bytescount;
|
||||
|
||||
buffersize = frames_to_bytes(substream->runtime,
|
||||
substream->runtime->buffer_size);
|
||||
|
||||
bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream);
|
||||
|
||||
if (bytescount > stream->bytescount)
|
||||
bytescount -= stream->bytescount;
|
||||
|
||||
pos = do_div(bytescount, buffersize);
|
||||
|
||||
return bytes_to_frames(substream->runtime, pos);
|
||||
}
|
||||
|
||||
static int acp_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 acp_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 acp_dma_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
|
||||
struct device *dev = component->dev;
|
||||
struct acp_dev_data *adata = dev_get_drvdata(dev);
|
||||
struct acp_stream *stream;
|
||||
int stream_id = cpu_dai->driver->id * 2 + substream->stream;
|
||||
|
||||
stream = adata->stream[stream_id];
|
||||
kfree(stream);
|
||||
adata->stream[stream_id] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver acp_pcm_component = {
|
||||
.name = DRV_NAME,
|
||||
.open = acp_dma_open,
|
||||
.close = acp_dma_close,
|
||||
.hw_params = acp_dma_hw_params,
|
||||
.pointer = acp_dma_pointer,
|
||||
.mmap = acp_dma_mmap,
|
||||
.pcm_construct = acp_dma_new,
|
||||
};
|
||||
|
||||
int acp_platform_register(struct device *dev)
|
||||
{
|
||||
struct acp_dev_data *adata = dev_get_drvdata(dev);
|
||||
struct snd_soc_dai_driver;
|
||||
unsigned int status;
|
||||
|
||||
status = devm_request_irq(dev, adata->i2s_irq, i2s_irq_handler,
|
||||
IRQF_SHARED, "ACP_I2S_IRQ", adata);
|
||||
if (status) {
|
||||
dev_err(dev, "ACP I2S IRQ request failed\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = devm_snd_soc_register_component(dev, &acp_pcm_component,
|
||||
adata->dai_driver,
|
||||
adata->num_dai);
|
||||
if (status) {
|
||||
dev_err(dev, "Fail to register acp i2s component\n");
|
||||
return status;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(acp_platform_register, SND_SOC_ACP_COMMON);
|
||||
|
||||
int acp_platform_unregister(struct device *dev)
|
||||
{
|
||||
struct acp_dev_data *adata = dev_get_drvdata(dev);
|
||||
|
||||
if (adata->mach_dev)
|
||||
platform_device_unregister(adata->mach_dev);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(acp_platform_unregister, SND_SOC_ACP_COMMON);
|
||||
|
||||
MODULE_DESCRIPTION("AMD ACP PCM Driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_ALIAS(DRV_NAME);
|
144
sound/soc/amd/acp/acp-renoir.c
Normal file
144
sound/soc/amd/acp/acp-renoir.c
Normal file
@ -0,0 +1,144 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
//
|
||||
// This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
// redistributing this file, you may do so under either license.
|
||||
//
|
||||
// Copyright(c) 2021 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
||||
//
|
||||
|
||||
/*
|
||||
* Hardware interface for Renoir ACP block
|
||||
*/
|
||||
|
||||
#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 "amd.h"
|
||||
|
||||
#define DRV_NAME "acp_asoc_renoir"
|
||||
|
||||
static struct snd_soc_dai_driver acp_renoir_dai[] = {
|
||||
{
|
||||
.name = "acp-i2s-sp",
|
||||
.id = I2S_SP_INSTANCE,
|
||||
.playback = {
|
||||
.stream_name = "I2S SP Playback",
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 96000,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "I2S SP Capture",
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
.ops = &asoc_acp_cpu_dai_ops,
|
||||
.probe = &asoc_acp_i2s_probe,
|
||||
},
|
||||
{
|
||||
.name = "acp-i2s-bt",
|
||||
.id = I2S_BT_INSTANCE,
|
||||
.playback = {
|
||||
.stream_name = "I2S BT Playback",
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 96000,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "I2S BT Capture",
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
.ops = &asoc_acp_cpu_dai_ops,
|
||||
.probe = &asoc_acp_i2s_probe,
|
||||
},
|
||||
};
|
||||
|
||||
static int renoir_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct acp_dev_data *adata;
|
||||
struct resource *res;
|
||||
|
||||
adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
|
||||
if (!adata)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!adata->acp_base)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
adata->i2s_irq = res->start;
|
||||
adata->dev = dev;
|
||||
adata->dai_driver = acp_renoir_dai;
|
||||
adata->num_dai = ARRAY_SIZE(acp_renoir_dai);
|
||||
|
||||
adata->machines = snd_soc_acpi_amd_acp_machines;
|
||||
acp_machine_select(adata);
|
||||
|
||||
dev_set_drvdata(dev, adata);
|
||||
acp_platform_register(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int renoir_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
acp_platform_unregister(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver renoir_driver = {
|
||||
.probe = renoir_audio_probe,
|
||||
.remove = renoir_audio_remove,
|
||||
.driver = {
|
||||
.name = "acp_asoc_renoir",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(renoir_driver);
|
||||
|
||||
MODULE_DESCRIPTION("AMD ACP Renoir Driver");
|
||||
MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
131
sound/soc/amd/acp/acp-sof-mach.c
Normal file
131
sound/soc/amd/acp/acp-sof-mach.c
Normal file
@ -0,0 +1,131 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
|
||||
//
|
||||
// This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
// redistributing this file, you may do so under either license.
|
||||
//
|
||||
// Copyright(c) 2021 Advanced Micro Devices, Inc.
|
||||
//
|
||||
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
||||
//
|
||||
|
||||
/*
|
||||
* SOF Machine Driver Support for ACP HW block
|
||||
*/
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "acp-mach.h"
|
||||
|
||||
static struct acp_card_drvdata sof_rt5682_rt1019_data = {
|
||||
.hs_cpu_id = I2S_SP,
|
||||
.amp_cpu_id = I2S_SP,
|
||||
.dmic_cpu_id = DMIC,
|
||||
.hs_codec_id = RT5682,
|
||||
.amp_codec_id = RT1019,
|
||||
.dmic_codec_id = DMIC,
|
||||
};
|
||||
|
||||
static struct acp_card_drvdata sof_rt5682_max_data = {
|
||||
.hs_cpu_id = I2S_SP,
|
||||
.amp_cpu_id = I2S_SP,
|
||||
.dmic_cpu_id = DMIC,
|
||||
.hs_codec_id = RT5682,
|
||||
.amp_codec_id = MAX98360A,
|
||||
.dmic_codec_id = DMIC,
|
||||
};
|
||||
|
||||
static struct acp_card_drvdata sof_rt5682s_max_data = {
|
||||
.hs_cpu_id = I2S_SP,
|
||||
.amp_cpu_id = I2S_SP,
|
||||
.dmic_cpu_id = DMIC,
|
||||
.hs_codec_id = RT5682S,
|
||||
.amp_codec_id = MAX98360A,
|
||||
.dmic_codec_id = DMIC,
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new acp_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Spk"),
|
||||
SOC_DAPM_PIN_SWITCH("Left Spk"),
|
||||
SOC_DAPM_PIN_SWITCH("Right Spk"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget acp_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Spk", NULL),
|
||||
SND_SOC_DAPM_SPK("Left Spk", NULL),
|
||||
SND_SOC_DAPM_SPK("Right Spk", NULL),
|
||||
};
|
||||
|
||||
static int acp_sof_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = NULL;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
if (!pdev->id_entry)
|
||||
return -EINVAL;
|
||||
|
||||
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
|
||||
if (!card)
|
||||
return -ENOMEM;
|
||||
|
||||
card->dev = dev;
|
||||
card->owner = THIS_MODULE;
|
||||
card->name = pdev->id_entry->name;
|
||||
card->dapm_widgets = acp_widgets;
|
||||
card->num_dapm_widgets = ARRAY_SIZE(acp_widgets);
|
||||
card->controls = acp_controls;
|
||||
card->num_controls = ARRAY_SIZE(acp_controls);
|
||||
card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
|
||||
|
||||
acp_sofdsp_dai_links_create(card);
|
||||
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"devm_snd_soc_register_card(%s) failed: %d\n",
|
||||
card->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id board_ids[] = {
|
||||
{
|
||||
.name = "rt5682-rt1019",
|
||||
.driver_data = (kernel_ulong_t)&sof_rt5682_rt1019_data
|
||||
},
|
||||
{
|
||||
.name = "rt5682-max",
|
||||
.driver_data = (kernel_ulong_t)&sof_rt5682_max_data
|
||||
},
|
||||
{
|
||||
.name = "rt5682s-max",
|
||||
.driver_data = (kernel_ulong_t)&sof_rt5682s_max_data
|
||||
},
|
||||
{ }
|
||||
};
|
||||
static struct platform_driver acp_asoc_audio = {
|
||||
.driver = {
|
||||
.name = "sof_mach",
|
||||
},
|
||||
.probe = acp_sof_probe,
|
||||
.id_table = board_ids,
|
||||
};
|
||||
|
||||
module_platform_driver(acp_asoc_audio);
|
||||
|
||||
MODULE_IMPORT_NS(SND_SOC_AMD_MACH);
|
||||
MODULE_DESCRIPTION("ACP chrome SOF audio support");
|
||||
MODULE_ALIAS("platform:rt5682-rt1019");
|
||||
MODULE_ALIAS("platform:rt5682-max");
|
||||
MODULE_ALIAS("platform:rt5682s-max");
|
||||
MODULE_LICENSE("GPL v2");
|
146
sound/soc/amd/acp/amd.h
Normal file
146
sound/soc/amd/acp/amd.h
Normal file
@ -0,0 +1,146 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
*
|
||||
* Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
||||
*/
|
||||
|
||||
#ifndef __AMD_ACP_H
|
||||
#define __AMD_ACP_H
|
||||
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
#include "chip_offset_byte.h"
|
||||
|
||||
#define I2S_SP_INSTANCE 0x00
|
||||
#define I2S_BT_INSTANCE 0x01
|
||||
|
||||
#define MEM_WINDOW_START 0x4000000
|
||||
|
||||
#define ACP_I2S_REG_START 0x1242400
|
||||
#define ACP_I2S_REG_END 0x1242810
|
||||
#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_SRAM_PTE_OFFSET 0x02052800
|
||||
|
||||
#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 65536
|
||||
#define MIN_BUFFER MAX_BUFFER
|
||||
#define FIFO_SIZE 0x100
|
||||
#define DMA_SIZE 0x40
|
||||
#define FRM_LEN 0x100
|
||||
|
||||
#define ACP3x_ITER_IRER_SAMP_LEN_MASK 0x38
|
||||
|
||||
#define ACP_MAX_STREAM 6
|
||||
|
||||
struct acp_stream {
|
||||
struct snd_pcm_substream *substream;
|
||||
int irq_bit;
|
||||
int dai_id;
|
||||
int id;
|
||||
u64 bytescount;
|
||||
u32 reg_offset;
|
||||
u32 pte_offset;
|
||||
u32 fifo_offset;
|
||||
};
|
||||
|
||||
struct acp_dev_data {
|
||||
char *name;
|
||||
struct device *dev;
|
||||
void __iomem *acp_base;
|
||||
unsigned int i2s_irq;
|
||||
|
||||
/* SOC specific dais */
|
||||
struct snd_soc_dai_driver *dai_driver;
|
||||
int num_dai;
|
||||
|
||||
struct acp_stream *stream[ACP_MAX_STREAM];
|
||||
|
||||
struct snd_soc_acpi_mach *machines;
|
||||
struct platform_device *mach_dev;
|
||||
};
|
||||
|
||||
extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops;
|
||||
|
||||
int asoc_acp_i2s_probe(struct snd_soc_dai *dai);
|
||||
int acp_platform_register(struct device *dev);
|
||||
int acp_platform_unregister(struct device *dev);
|
||||
|
||||
int acp_machine_select(struct acp_dev_data *adata);
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[];
|
||||
|
||||
static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction)
|
||||
{
|
||||
u64 byte_count, low = 0, high = 0;
|
||||
|
||||
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
switch (dai_id) {
|
||||
case I2S_BT_INSTANCE:
|
||||
high = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_HIGH);
|
||||
low = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_LOW);
|
||||
break;
|
||||
case I2S_SP_INSTANCE:
|
||||
high = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH);
|
||||
low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW);
|
||||
break;
|
||||
default:
|
||||
dev_err(adata->dev, "Invalid dai id %x\n", dai_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
switch (dai_id) {
|
||||
case I2S_BT_INSTANCE:
|
||||
high = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_HIGH);
|
||||
low = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_LOW);
|
||||
break;
|
||||
case I2S_SP_INSTANCE:
|
||||
high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH);
|
||||
low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW);
|
||||
break;
|
||||
default:
|
||||
dev_err(adata->dev, "Invalid dai id %x\n", dai_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
/* Get 64 bit value from two 32 bit registers */
|
||||
byte_count = (high << 32) | low;
|
||||
|
||||
return byte_count;
|
||||
}
|
||||
|
||||
#endif
|
76
sound/soc/amd/acp/chip_offset_byte.h
Normal file
76
sound/soc/amd/acp/chip_offset_byte.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
|
||||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
*
|
||||
* Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
||||
*/
|
||||
|
||||
#ifndef _ACP_IP_OFFSET_HEADER
|
||||
#define _ACP_IP_OFFSET_HEADER
|
||||
|
||||
#define ACPAXI2AXI_ATU_CTRL 0xC40
|
||||
#define ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0xC20
|
||||
#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0xC24
|
||||
#define ACP_EXTERNAL_INTR_ENB 0x1800
|
||||
#define ACP_EXTERNAL_INTR_CNTL 0x1804
|
||||
#define ACP_EXTERNAL_INTR_STAT 0x1808
|
||||
#define ACP_I2S_PIN_CONFIG 0x1400
|
||||
#define ACP_SCRATCH_REG_0 0x12800
|
||||
|
||||
/* Registers from ACP_AUDIO_BUFFERS block */
|
||||
|
||||
#define ACP_I2S_RX_RINGBUFADDR 0x2000
|
||||
#define ACP_I2S_RX_RINGBUFSIZE 0x2004
|
||||
#define ACP_I2S_RX_LINKPOSITIONCNTR 0x2008
|
||||
#define ACP_I2S_RX_FIFOADDR 0x200C
|
||||
#define ACP_I2S_RX_FIFOSIZE 0x2010
|
||||
#define ACP_I2S_RX_DMA_SIZE 0x2014
|
||||
#define ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x2018
|
||||
#define ACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x201C
|
||||
#define ACP_I2S_RX_INTR_WATERMARK_SIZE 0x2020
|
||||
#define ACP_I2S_TX_RINGBUFADDR 0x2024
|
||||
#define ACP_I2S_TX_RINGBUFSIZE 0x2028
|
||||
#define ACP_I2S_TX_LINKPOSITIONCNTR 0x202C
|
||||
#define ACP_I2S_TX_FIFOADDR 0x2030
|
||||
#define ACP_I2S_TX_FIFOSIZE 0x2034
|
||||
#define ACP_I2S_TX_DMA_SIZE 0x2038
|
||||
#define ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x203C
|
||||
#define ACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x2040
|
||||
#define ACP_I2S_TX_INTR_WATERMARK_SIZE 0x2044
|
||||
#define ACP_BT_RX_RINGBUFADDR 0x2048
|
||||
#define ACP_BT_RX_RINGBUFSIZE 0x204C
|
||||
#define ACP_BT_RX_LINKPOSITIONCNTR 0x2050
|
||||
#define ACP_BT_RX_FIFOADDR 0x2054
|
||||
#define ACP_BT_RX_FIFOSIZE 0x2058
|
||||
#define ACP_BT_RX_DMA_SIZE 0x205C
|
||||
#define ACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x2060
|
||||
#define ACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x2064
|
||||
#define ACP_BT_RX_INTR_WATERMARK_SIZE 0x2068
|
||||
#define ACP_BT_TX_RINGBUFADDR 0x206C
|
||||
#define ACP_BT_TX_RINGBUFSIZE 0x2070
|
||||
#define ACP_BT_TX_LINKPOSITIONCNTR 0x2074
|
||||
#define ACP_BT_TX_FIFOADDR 0x2078
|
||||
#define ACP_BT_TX_FIFOSIZE 0x207C
|
||||
#define ACP_BT_TX_DMA_SIZE 0x2080
|
||||
#define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x2084
|
||||
#define ACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x2088
|
||||
#define ACP_BT_TX_INTR_WATERMARK_SIZE 0x208C
|
||||
|
||||
#define ACP_I2STDM_IER 0x2400
|
||||
#define ACP_I2STDM_IRER 0x2404
|
||||
#define ACP_I2STDM_RXFRMT 0x2408
|
||||
#define ACP_I2STDM_ITER 0x240C
|
||||
#define ACP_I2STDM_TXFRMT 0x2410
|
||||
|
||||
/* Registers from ACP_BT_TDM block */
|
||||
|
||||
#define ACP_BTTDM_IER 0x2800
|
||||
#define ACP_BTTDM_IRER 0x2804
|
||||
#define ACP_BTTDM_RXFRMT 0x2808
|
||||
#define ACP_BTTDM_ITER 0x280C
|
||||
#define ACP_BTTDM_TXFRMT 0x2810
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user