driver:amd:enabling support for sound wire

Enabling sound wire support for amd platform

Signed-off-by: maruthi machani <maruthi.machani@amd.corp-partner.google.com>
This commit is contained in:
maruthi machani 2023-11-06 11:52:21 +05:30 committed by Kai Vehmanen
parent f56559c059
commit 3858532c76
9 changed files with 655 additions and 1 deletions

View File

@ -4,10 +4,12 @@ add_local_sources(sof
acp_dma.c
acp_sp_dai.c
acp_hs_dai.c
acp_sw_audio_dai.c
interrupt.c
ipc.c
acp_bt_dma.c
acp_sp_dma.c
acp_hs_dma.c
acp_sw_audio_dma.c
acp_dmic_dma.c
)

View File

@ -0,0 +1,114 @@
// SPDX-License-Identifier: BSD-3-Clause
//
//Copyright(c) 2023 AMD. All rights reserved.
//
//Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com>
// Maruthi Machani <maruthi.machani@amd.com>
#include <sof/drivers/acp_dai_dma.h>
#include <sof/lib/uuid.h>
#include <sof/trace/trace.h>
/* 8f00c3bb-e835-4767-9a34-b8ec1041e56b */
DECLARE_SOF_UUID("swaudiodai", swaudiodai_uuid, 0x8f00c3bb, 0xe835, 0x4767,
0x9a, 0x34, 0xb8, 0xec, 0x10, 0x41, 0xe5, 0x6b);
DECLARE_TR_CTX(swaudiodai_tr, SOF_UUID(swaudiodai_uuid), LOG_LEVEL_INFO);
static inline int swaudiodai_set_config(struct dai *dai, struct ipc_config_dai *common_config,
const void *spec_config)
{
const struct sof_ipc_dai_config *config = spec_config;
struct acp_pdata *acpdata = dai_get_drvdata(dai);
acpdata->config = *config;
acpdata->sdw_params = config->acpsdw;
return 0;
}
static int swaudiodai_trigger(struct dai *dai, int cmd, int direction)
{
/* nothing to do on rembrandt for SW dai */
return 0;
}
static int swaudiodai_probe(struct dai *dai)
{
struct acp_pdata *acp;
dai_info(dai, "#$AMD$# SW dai probe");
/* allocate private data */
acp = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*acp));
if (!acp) {
dai_err(dai, "SW dai probe alloc failed");
return -ENOMEM;
}
dai_set_drvdata(dai, acp);
return 0;
}
static int swaudiodai_remove(struct dai *dai)
{
struct acp_pdata *acp = dai_get_drvdata(dai);
dai_info(dai, "swaudiodai_remove");
rfree(acp);
dai_set_drvdata(dai, NULL);
return 0;
}
static int swaudiodai_get_fifo(struct dai *dai, int direction, int stream_id)
{
switch (direction) {
case DAI_DIR_PLAYBACK:
case DAI_DIR_CAPTURE:
return dai_fifo(dai, direction);
default:
dai_err(dai, "Invalid direction");
return -EINVAL;
}
}
static int swaudiodai_get_handshake(struct dai *dai, int direction, int stream_id)
{
int handshake = dai->plat_data.fifo[direction].handshake;
interrupt_get_irq(handshake, "irqsteer1");
return dai->plat_data.fifo[direction].handshake;
}
static int swaudiodai_get_hw_params(struct dai *dai,
struct sof_ipc_stream_params *params,
int dir)
{
struct acp_pdata *acpdata = dai_get_drvdata(dai);
/* DAI currently supports only these parameters */
params->rate = acpdata->sdw_params.rate;
params->channels = acpdata->sdw_params.channels;
params->buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
params->frame_fmt = SOF_IPC_FRAME_S16_LE;
return 0;
}
const struct dai_driver acp_swaudiodai_driver = {
.type = SOF_DAI_AMD_SW_AUDIO,
.uid = SOF_UUID(swaudiodai_uuid),
.tctx = &swaudiodai_tr,
.dma_dev = DMA_DEV_SW,
.dma_caps = DMA_CAP_SW,
.ops = {
.trigger = swaudiodai_trigger,
.set_config = swaudiodai_set_config,
.probe = swaudiodai_probe,
.remove = swaudiodai_remove,
.get_fifo = swaudiodai_get_fifo,
.get_handshake = swaudiodai_get_handshake,
.get_hw_params = swaudiodai_get_hw_params,
},
};

View File

@ -0,0 +1,523 @@
// SPDX-License-Identifier: BSD-3-Clause//
//Copyright(c) 2023 AMD. All rights reserved.
//
//Author: Basavaraj Hiregoudar <basavaraj.hiregoudar@amd.com>
// Maruthi Machani <maruthi.machani@amd.com>
#include <sof/audio/component.h>
#include <sof/drivers/acp_dai_dma.h>
#include <sof/lib/notifier.h>
#include <platform/chip_registers.h>
#include <rtos/wait.h>
#include <sof/lib/uuid.h>
#include <sof/trace/trace.h>
#ifdef CONFIG_ACP_6_3
/*b414df09-9e31-4c59-8657-7afc8deba70c*/
DECLARE_SOF_UUID("acp-sw-audio", acp_sw_audio_uuid, 0xb414df09, 0x9e31, 0x4c59,
0x86, 0x57, 0x7a, 0xfc, 0x8d, 0xeb, 0xa7, 0x0c);
DECLARE_TR_CTX(acp_sw_audio_tr, SOF_UUID(acp_sw_audio_uuid), LOG_LEVEL_INFO);
//initialization of soundwire-0 fifos(Audio, BT and HS)
#define SW0_AUDIO_FIFO_SIZE 128
#define SW0_AUDIO_TX_FIFO_ADDR 0
#define SW0_AUDIO_RX_FIFO_ADDR (SW0_AUDIO_TX_FIFO_ADDR + SW0_AUDIO_FIFO_SIZE)
#define SW0_BT_FIFO_SIZE 128
#define SW0_BT_TX_FIFO_ADDR (SW0_AUDIO_RX_FIFO_ADDR + SW0_AUDIO_FIFO_SIZE)
#define SW0_BT_RX_FIFO_ADDR (SW0_BT_TX_FIFO_ADDR + SW0_BT_FIFO_SIZE)
#define SW0_HS_FIFO_SIZE 128
#define SW0_HS_TX_FIFO_ADDR (SW0_BT_RX_FIFO_ADDR + SW0_BT_FIFO_SIZE)
#define SW0_HS_RX_FIFO_ADDR (SW0_HS_TX_FIFO_ADDR + SW0_HS_FIFO_SIZE)
//initialization of soundwire-1 fifo
#define SW1_FIFO_SIZE 128
#define SW1_TX_FIFO_ADDR (SW0_HS_RX_FIFO_ADDR + SW1_FIFO_SIZE)
#define SW1_RX_FIFO_ADDR (SW1_TX_FIFO_ADDR + SW1_FIFO_SIZE)
static uint32_t sw_audio_buff_size_playback;
static uint32_t sw_audio_buff_size_capture;
struct sw_dev_register {
uint32_t sw_dev_en;
uint32_t sw_dev_en_status;
uint32_t sw_dev_fifo_addr;
uint32_t fifo_addr;
uint32_t sw_dev_fifo_size;
uint32_t fifo_size;
uint32_t sw_dev_ringbuff_addr;
uint32_t sw_dev_ringbuff_size;
uint32_t sw_dev_dma_size;
uint32_t sw_dev_dma_watermark;
uint32_t sw_dev_dma_intr_status;
uint32_t sw_dev_dma_intr_cntl;
uint32_t statusindex;
};
static struct sw_dev_register sw_dev[8] = {
{ACP_SW_HS_RX_EN, ACP_SW_HS_RX_EN_STATUS, ACP_HS_RX_FIFOADDR, SW0_HS_RX_FIFO_ADDR,
ACP_HS_RX_FIFOSIZE, SW0_HS_FIFO_SIZE, ACP_HS_RX_RINGBUFADDR, ACP_HS_RX_RINGBUFSIZE,
ACP_HS_RX_DMA_SIZE, ACP_HS_RX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_INTR_CNTL, 0},
{ACP_SW_HS_TX_EN, ACP_SW_HS_TX_EN_STATUS, ACP_HS_TX_FIFOADDR, SW0_HS_TX_FIFO_ADDR,
ACP_HS_TX_FIFOSIZE, SW0_HS_FIFO_SIZE, ACP_HS_TX_RINGBUFADDR, ACP_HS_TX_RINGBUFSIZE,
ACP_HS_TX_DMA_SIZE, ACP_HS_TX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_INTR_CNTL, 1},
{ACP_P1_SW_BT_RX_EN, ACP_P1_SW_BT_RX_EN_STATUS, ACP_P1_BT_RX_FIFOADDR, SW1_RX_FIFO_ADDR,
ACP_P1_BT_RX_FIFOSIZE, SW1_FIFO_SIZE, ACP_P1_BT_RX_RINGBUFADDR, ACP_P1_BT_RX_RINGBUFSIZE,
ACP_P1_BT_RX_DMA_SIZE, ACP_P1_BT_RX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT1, ACP_DSP0_INTR_CNTL1,
2},
{ACP_P1_SW_BT_TX_EN, ACP_P1_SW_BT_TX_EN_STATUS, ACP_P1_BT_TX_FIFOADDR, SW1_TX_FIFO_ADDR,
ACP_P1_BT_TX_FIFOSIZE, SW1_FIFO_SIZE, ACP_P1_BT_TX_RINGBUFADDR, ACP_P1_BT_TX_RINGBUFSIZE,
ACP_P1_BT_TX_DMA_SIZE, ACP_P1_BT_TX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT1, ACP_DSP0_INTR_CNTL1,
3},
{ACP_SW_AUDIO_RX_EN, ACP_SW_AUDIO_RX_EN_STATUS, ACP_AUDIO_RX_FIFOADDR, SW0_AUDIO_RX_FIFO_ADDR,
ACP_AUDIO_RX_FIFOSIZE, SW0_AUDIO_FIFO_SIZE, ACP_AUDIO_RX_RINGBUFADDR, ACP_AUDIO_RX_RINGBUFSIZE,
ACP_AUDIO_RX_DMA_SIZE, ACP_AUDIO_RX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_INTR_CNTL, 4},
{ACP_SW_AUDIO_TX_EN, ACP_SW_AUDIO_TX_EN_STATUS, ACP_AUDIO_TX_FIFOADDR, SW0_AUDIO_TX_FIFO_ADDR,
ACP_AUDIO_TX_FIFOSIZE, SW0_AUDIO_FIFO_SIZE, ACP_AUDIO_TX_RINGBUFADDR, ACP_AUDIO_TX_RINGBUFSIZE,
ACP_AUDIO_TX_DMA_SIZE, ACP_AUDIO_TX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_INTR_CNTL, 5},
{ACP_SW_BT_RX_EN, ACP_SW_BT_RX_EN_STATUS, ACP_BT_RX_FIFOADDR, SW0_BT_RX_FIFO_ADDR,
ACP_BT_RX_FIFOSIZE, SW0_BT_FIFO_SIZE, ACP_BT_RX_RINGBUFADDR, ACP_BT_RX_RINGBUFSIZE,
ACP_BT_RX_DMA_SIZE, ACP_BT_RX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_INTR_CNTL, 2},
{ACP_SW_BT_TX_EN, ACP_SW_BT_TX_EN_STATUS, ACP_BT_TX_FIFOADDR, SW0_BT_TX_FIFO_ADDR,
ACP_BT_TX_FIFOSIZE, SW0_BT_FIFO_SIZE, ACP_BT_TX_RINGBUFADDR, ACP_BT_TX_RINGBUFSIZE,
ACP_BT_TX_DMA_SIZE, ACP_BT_TX_INTR_WATERMARK_SIZE, ACP_DSP0_INTR_STAT, ACP_DSP0_INTR_CNTL, 3}
};
/* allocate next free DMA channel */
static struct dma_chan_data *acp_dai_sw_audio_dma_channel_get(struct dma *dma,
unsigned int req_chan)
{
k_spinlock_key_t key;
struct dma_chan_data *channel;
key = k_spin_lock(&dma->lock);
if (req_chan >= dma->plat_data.channels) {
k_spin_unlock(&dma->lock, key);
tr_err(&acp_sw_audio_tr, "Channel %d not in range", req_chan);
return NULL;
}
channel = &dma->chan[req_chan];
if (channel->status != COMP_STATE_INIT) {
k_spin_unlock(&dma->lock, key);
tr_err(&acp_sw_audio_tr, "channel already in use %d", req_chan);
return NULL;
}
atomic_add(&dma->num_channels_busy, 1);
channel->status = COMP_STATE_READY;
k_spin_unlock(&dma->lock, key);
return channel;
}
/* channel must not be running when this is called */
static void acp_dai_sw_audio_dma_channel_put(struct dma_chan_data *channel)
{
k_spinlock_key_t key;
notifier_unregister_all(NULL, channel);
key = k_spin_lock(&channel->dma->lock);
channel->status = COMP_STATE_INIT;
atomic_sub(&channel->dma->num_channels_busy, 1);
k_spin_unlock(&channel->dma->lock, key);
}
static int acp_dai_sw_audio_dma_start(struct dma_chan_data *channel)
{
uint32_t sw0_audio_tx_en = 0;
uint32_t sw0_audio_rx_en = 0;
uint32_t acp_pdm_en;
int i;
for (i = 0; i < 8; i += 2) {
sw0_audio_tx_en |= io_reg_read(PU_REGISTER_BASE + sw_dev[i].sw_dev_en);
sw0_audio_rx_en |= io_reg_read(PU_REGISTER_BASE + sw_dev[i + 1].sw_dev_en);
}
acp_pdm_en = io_reg_read(PU_REGISTER_BASE + ACP_WOV_PDM_ENABLE);
if (!sw0_audio_tx_en && !sw0_audio_rx_en && !acp_pdm_en) {
/* Request SMU to set aclk to 600 Mhz */
acp_change_clock_notify(600000000);
io_reg_write(PU_REGISTER_BASE + ACP_CLKMUX_SEL, ACP_ACLK_CLK_SEL);
}
switch (channel->direction) {
case DMA_DIR_MEM_TO_DEV:
case DMA_DIR_DEV_TO_MEM:
channel->status = COMP_STATE_ACTIVE;
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_en, 1);
poll_for_register_delay(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_en_status,
0x1, 0x1, 15);
break;
default:
tr_err(&acp_sw_audio_tr, "Start direction not defined %d",
channel->direction);
return -EINVAL;
}
return 0;
}
static int acp_dai_sw_audio_dma_release(struct dma_chan_data *channel)
{
/* nothing to do on rembrandt */
return 0;
}
static int acp_dai_sw_audio_dma_pause(struct dma_chan_data *channel)
{
/* nothing to do on rembrandt */
return 0;
}
static int acp_dai_sw_audio_dma_stop(struct dma_chan_data *channel)
{
uint32_t sw0_audio_tx_en = 0;
uint32_t sw0_audio_rx_en = 0;
uint32_t acp_pdm_en;
int i;
switch (channel->status) {
case COMP_STATE_READY:
case COMP_STATE_PREPARE:
return 0;
case COMP_STATE_PAUSED:
case COMP_STATE_ACTIVE:
break;
default:
return -EINVAL;
}
channel->status = COMP_STATE_READY;
switch (channel->direction) {
case DMA_DIR_MEM_TO_DEV:
case DMA_DIR_DEV_TO_MEM:
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_en, 0);
poll_for_register_delay(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_en_status,
0x1, 0x0, 15);
break;
default:
tr_err(&acp_sw_audio_tr, "Stop direction not defined %d",
channel->direction);
return -EINVAL;
}
for (i = 0; i < 8; i += 2) {
sw0_audio_tx_en |= io_reg_read(PU_REGISTER_BASE + sw_dev[i].sw_dev_en);
sw0_audio_rx_en |= io_reg_read(PU_REGISTER_BASE + sw_dev[i + 1].sw_dev_en);
}
acp_pdm_en = io_reg_read(PU_REGISTER_BASE + ACP_WOV_PDM_ENABLE);
if (!sw0_audio_tx_en && !sw0_audio_rx_en) {
/* Request SMU to scale down aclk to minimum clk */
if (!acp_pdm_en) {
io_reg_write(PU_REGISTER_BASE + ACP_CLKMUX_SEL, ACP_INTERNAL_CLK_SEL);
acp_change_clock_notify(0);
}
}
return 0;
}
static int acp_dai_sw_audio_dma_status(struct dma_chan_data *channel,
struct dma_chan_status *status,
uint8_t direction)
{
/* nothing to do on rembrandt */
return 0;
}
/* set the DMA channel configuration, source/target address, buffer sizes */
static int acp_dai_sw_audio_dma_set_config(struct dma_chan_data *channel,
struct dma_sg_config *config)
{
uint32_t sw0_audio_ringbuff_addr;
uint32_t sw0_audio_fifo_addr;
if (!config->cyclic) {
tr_err(&acp_sw_audio_tr, "cyclic configurations only supported!");
return -EINVAL;
}
if (config->scatter) {
tr_err(&acp_sw_audio_tr, "scatter enabled, that is not supported for now!");
return -EINVAL;
}
channel->is_scheduling_source = true;
channel->direction = config->direction;
switch (channel->direction) {
case DMA_DIR_MEM_TO_DEV:
sw_audio_buff_size_playback = config->elem_array.elems[0].size *
config->elem_array.count;
/* SW Transmit FIFO Address and FIFO Size*/
sw0_audio_fifo_addr = sw_dev[channel->index].fifo_addr;
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_fifo_addr,
sw0_audio_fifo_addr);
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_fifo_size,
sw_dev[channel->index].fifo_size);
/* Transmit RINGBUFFER Address and size*/
config->elem_array.elems[0].src = (config->elem_array.elems[0].src &
ACP_DRAM_ADDRESS_MASK);
sw0_audio_ringbuff_addr = (config->elem_array.elems[0].src | ACP_SRAM);
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_ringbuff_addr,
sw0_audio_ringbuff_addr);
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_ringbuff_size,
sw_audio_buff_size_playback);
/* Transmit DMA transfer size in bytes */
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_dma_size,
(uint32_t)(64/*ACP_DMA_TRANS_SIZE_128*/));
/* Watermark size for SW transmit FIFO - Half of SW buffer size */
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_dma_watermark,
(sw_audio_buff_size_playback >> 1));
break;
case DMA_DIR_DEV_TO_MEM:
sw_audio_buff_size_capture = config->elem_array.elems[0].size *
config->elem_array.count;
/* SW Receive FIFO Address and FIFO Size*/
sw0_audio_fifo_addr = sw_dev[channel->index].fifo_addr;
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_fifo_addr,
sw0_audio_fifo_addr);
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_fifo_size,
sw_dev[channel->index].fifo_size);
/* Receive RINGBUFFER Address and size*/
config->elem_array.elems[0].dest =
(config->elem_array.elems[0].dest & ACP_DRAM_ADDRESS_MASK);
sw0_audio_ringbuff_addr = (config->elem_array.elems[0].dest | ACP_SRAM);
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_ringbuff_addr,
sw0_audio_ringbuff_addr);
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_ringbuff_size,
sw_audio_buff_size_capture);
/* Receive DMA transfer size in bytes */
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_dma_size,
(uint32_t)(64/*ACP_DMA_TRANS_SIZE_128*/));
/* Watermark size for receive fifo - Half of SW buffer size*/
io_reg_write(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_dma_watermark,
sw_audio_buff_size_capture >> 1);
break;
default:
tr_err(&acp_sw_audio_tr, "Config channel direction undefined %d",
channel->direction);
return -EINVAL;
}
return 0;
}
static int acp_dai_sw_audio_dma_copy(struct dma_chan_data *channel, int bytes,
uint32_t flags)
{
struct dma_cb_data next = {
.channel = channel,
.elem.size = bytes,
};
notifier_event(channel, NOTIFIER_ID_DMA_COPY,
NOTIFIER_TARGET_CORE_LOCAL, &next, sizeof(next));
return 0;
}
static int acp_dai_sw_audio_dma_probe(struct dma *dma)
{
int channel;
if (dma->chan) {
tr_err(&acp_sw_audio_tr, "Repeated probe");
return -EEXIST;
}
dma->chan = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0,
SOF_MEM_CAPS_RAM, dma->plat_data.channels *
sizeof(struct dma_chan_data));
if (!dma->chan) {
tr_err(&acp_sw_audio_tr, "Probe failure,unable to allocate channel descriptors");
return -ENOMEM;
}
for (channel = 0; channel < dma->plat_data.channels; channel++) {
dma->chan[channel].dma = dma;
dma->chan[channel].index = channel;
dma->chan[channel].status = COMP_STATE_INIT;
}
atomic_init(&dma->num_channels_busy, 0);
return 0;
}
static int acp_dai_sw_audio_dma_remove(struct dma *dma)
{
if (!dma->chan) {
tr_err(&acp_sw_audio_tr, "remove called without probe,it's a no-op");
return 0;
}
rfree(dma->chan);
dma->chan = NULL;
return 0;
}
static int acp_dai_sw_audio_dma_get_data_size(struct dma_chan_data *channel,
uint32_t *avail, uint32_t *free)
{
if (channel->direction == DMA_DIR_MEM_TO_DEV) {
*free = sw_audio_buff_size_playback >> 1;
*avail = sw_audio_buff_size_playback >> 1;
} else if (channel->direction == DMA_DIR_DEV_TO_MEM) {
*free = sw_audio_buff_size_capture >> 1;
*avail = sw_audio_buff_size_capture >> 1;
} else {
tr_err(&acp_sw_audio_tr, "Channel direction not defined %d", channel->direction);
return -EINVAL;
}
return 0;
}
static int acp_dai_sw_audio_dma_get_attribute(struct dma *dma, uint32_t type, uint32_t *value)
{
switch (type) {
case DMA_ATTR_BUFFER_ALIGNMENT:
case DMA_ATTR_COPY_ALIGNMENT:
*value = ACP_DMA_BUFFER_ALIGN_128;
break;
case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT:
*value = PLATFORM_DCACHE_ALIGN;
break;
case DMA_ATTR_BUFFER_PERIOD_COUNT:
*value = ACP_DAI_DMA_BUFFER_PERIOD_COUNT;
break;
default:
return -ENOENT;
}
return 0;
}
static int acp_dai_sw_audio_dma_interrupt(struct dma_chan_data *channel, enum dma_irq_cmd cmd)
{
uint32_t status = 0;
acp_dsp0_intr_stat_t acp_intr_stat;
acp_dsp0_intr_cntl_t acp_intr_cntl;
acp_dsp0_intr_stat1_t acp_intr_stat1;
acp_dsp0_intr_cntl1_t acp_intr_cntl1;
if (channel->status == COMP_STATE_INIT)
return 0;
switch (cmd) {
case DMA_IRQ_STATUS_GET:
switch (channel->index) {
case SDW1_ACP_P1_SW_BT_TX_EN_CH:
case SDW1_ACP_P1_SW_BT_RX_EN_CH:
acp_intr_stat1 = (acp_dsp0_intr_stat1_t)dma_reg_read(channel->dma,
sw_dev[channel->index].sw_dev_dma_intr_status);
status = acp_intr_stat1.bits.audio_buffer_int_stat;
break;
default:
acp_intr_stat = (acp_dsp0_intr_stat_t)dma_reg_read(channel->dma,
sw_dev[channel->index].sw_dev_dma_intr_status);
status = acp_intr_stat.bits.audio_buffer_int_stat;
break;
}
return (status & (1 << sw_dev[channel->index].statusindex));
case DMA_IRQ_CLEAR:
switch (channel->index) {
case SDW1_ACP_P1_SW_BT_TX_EN_CH:
case SDW1_ACP_P1_SW_BT_RX_EN_CH:
acp_intr_stat1.u32all = 0;
acp_intr_stat1.bits.audio_buffer_int_stat =
(1 << sw_dev[channel->index].statusindex);
status = acp_intr_stat1.u32all;
dma_reg_write(channel->dma, sw_dev[channel->index].sw_dev_dma_intr_status,
status);
break;
default:
acp_intr_stat.u32all = 0;
acp_intr_stat.bits.audio_buffer_int_stat =
(1 << sw_dev[channel->index].statusindex);
status = acp_intr_stat.u32all;
dma_reg_write(channel->dma, sw_dev[channel->index].sw_dev_dma_intr_status,
status);
break;
}
return 0;
case DMA_IRQ_MASK:
switch (channel->index) {
case SDW1_ACP_P1_SW_BT_TX_EN_CH:
case SDW1_ACP_P1_SW_BT_RX_EN_CH:
acp_intr_cntl1 = (acp_dsp0_intr_cntl1_t)dma_reg_read(channel->dma,
sw_dev[channel->index].sw_dev_dma_intr_cntl);
acp_intr_cntl1.bits.audio_buffer_int_mask &=
(~(1 << sw_dev[channel->index].statusindex));
status = acp_intr_cntl1.u32all;
dma_reg_write(channel->dma, sw_dev[channel->index].sw_dev_dma_intr_cntl,
status);
break;
default:
acp_intr_cntl = (acp_dsp0_intr_cntl_t)
io_reg_read(PU_REGISTER_BASE + sw_dev[channel->index].sw_dev_dma_intr_cntl);
acp_intr_cntl.bits.audio_buffer_int_mask &=
(~(1 << sw_dev[channel->index].statusindex));
status = acp_intr_cntl.u32all;
dma_reg_write(channel->dma, sw_dev[channel->index].sw_dev_dma_intr_cntl,
status);
break;
}
return 0;
case DMA_IRQ_UNMASK:
switch (channel->index) {
case SDW1_ACP_P1_SW_BT_TX_EN_CH:
case SDW1_ACP_P1_SW_BT_RX_EN_CH:
acp_intr_cntl1 = (acp_dsp0_intr_cntl1_t)dma_reg_read(channel->dma,
sw_dev[channel->index].sw_dev_dma_intr_cntl);
acp_intr_cntl1.bits.audio_buffer_int_mask |=
(1 << sw_dev[channel->index].statusindex);
status = acp_intr_cntl1.u32all;
dma_reg_write(channel->dma, sw_dev[channel->index].sw_dev_dma_intr_cntl,
status);
break;
default:
acp_intr_cntl = (acp_dsp0_intr_cntl_t)dma_reg_read(channel->dma,
sw_dev[channel->index].sw_dev_dma_intr_cntl);
acp_intr_cntl.bits.audio_buffer_int_mask |=
(1 << sw_dev[channel->index].statusindex);
status = acp_intr_cntl.u32all;
dma_reg_write(channel->dma, sw_dev[channel->index].sw_dev_dma_intr_cntl,
status);
break;
}
return 0;
default:
return -EINVAL;
}
}
const struct dma_ops acp_dai_sw_audio_dma_ops = {
.channel_get = acp_dai_sw_audio_dma_channel_get,
.channel_put = acp_dai_sw_audio_dma_channel_put,
.start = acp_dai_sw_audio_dma_start,
.stop = acp_dai_sw_audio_dma_stop,
.pause = acp_dai_sw_audio_dma_pause,
.release = acp_dai_sw_audio_dma_release,
.copy = acp_dai_sw_audio_dma_copy,
.status = acp_dai_sw_audio_dma_status,
.set_config = acp_dai_sw_audio_dma_set_config,
.interrupt = acp_dai_sw_audio_dma_interrupt,
.probe = acp_dai_sw_audio_dma_probe,
.remove = acp_dai_sw_audio_dma_remove,
.get_data_size = acp_dai_sw_audio_dma_get_data_size,
.get_attribute = acp_dai_sw_audio_dma_get_attribute,
};
#endif

View File

@ -24,4 +24,11 @@ struct sof_ipc_dai_acp_params {
uint32_t fsync_rate;
uint32_t tdm_slots;
} __attribute__((packed, aligned(4)));
/* ACP Configuration Request - SOF_IPC_DAI_AMD_SDW_CONFIG */
struct sof_ipc_dai_acp_sdw_params {
uint32_t reserved0;
uint32_t rate;
uint32_t channels;
} __attribute__((packed, aligned(4)));
#endif /* __IPC_DAI_AMD_H__ */

View File

@ -94,6 +94,7 @@ enum sof_ipc_dai_type {
SOF_DAI_AMD_SP_VIRTUAL, /**<Amd SP VIRTUAL */
SOF_DAI_AMD_HS_VIRTUAL, /**<Amd HS VIRTUAL */
SOF_DAI_IMX_MICFIL, /**< i.MX MICFIL */
SOF_DAI_AMD_SW_AUDIO /**<Amd SW AUDIO */
};
/* general purpose DAI configuration */
@ -124,6 +125,7 @@ struct sof_ipc_dai_config {
struct sof_ipc_dai_acp_params acphs;
struct sof_ipc_dai_afe_params afe;
struct sof_ipc_dai_micfil_params micfil;
struct sof_ipc_dai_acp_sdw_params acpsdw;
};
} __attribute__((packed, aligned(4)));

View File

@ -29,7 +29,7 @@
/** \brief SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
#define SOF_ABI_MINOR 28
#define SOF_ABI_MINOR 29
#define SOF_ABI_PATCH 0
/** \brief SOF ABI version number. Format within 32bit word is MMmmmppp */

View File

@ -50,11 +50,13 @@ extern const struct dai_driver acp_btdai_driver;
extern const struct dai_driver acp_dmic_dai_driver;
extern const struct dai_driver acp_hsdai_driver;
extern const struct dai_driver acp_hs_virtual_dai_driver;
extern const struct dai_driver acp_swaudiodai_driver;
/* ACP private data */
struct acp_pdata {
struct sof_ipc_dai_config config;
struct sof_ipc_dai_acpdmic_params dmic_params;
struct sof_ipc_dai_acp_params params;
struct sof_ipc_dai_acp_sdw_params sdw_params;
};
#endif /* __SOF_DRIVERS_ACPDMA_H__ */

View File

@ -84,6 +84,7 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void
break;
case SOF_DAI_AMD_HS:
case SOF_DAI_AMD_HS_VIRTUAL:
case SOF_DAI_AMD_SW_AUDIO:
channel = dai_get_handshake(dd->dai, dai->direction,
dd->stream_id);
break;
@ -178,6 +179,7 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev)
break;
case SOF_DAI_AMD_HS:
case SOF_DAI_AMD_HS_VIRTUAL:
case SOF_DAI_AMD_SW_AUDIO:
dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S16_LE;
break;
case SOF_DAI_MEDIATEK_AFE:

View File

@ -58,6 +58,7 @@ struct comp_buffer;
#define DMA_CAP_SP_VIRTUAL BIT(6) /**< SP VIRTUAL DMA */
#define DMA_CAP_HS_VIRTUAL BIT(7) /**< HS VIRTUAL DMA */
#define DMA_CAP_HS BIT(8) /**< HS DMA */
#define DMA_CAP_SW BIT(9) /**< SW DMA */
/* DMA dev type bitmasks used to define the type of DMA */
@ -76,6 +77,7 @@ struct comp_buffer;
#define DMA_DEV_HS_VIRTUAL BIT(12) /**< connectable to ACP HS VIRTUAL I2S */
#define DMA_DEV_HS BIT(13) /**< connectable to ACP HS I2S */
#define DMA_DEV_MICFIL BIT(14) /**< connectable to MICFIL fifo */
#define DMA_DEV_SW BIT(15) /**< connectable to ACP SW */
/* DMA access privilege flag */
#define DMA_ACCESS_EXCLUSIVE 1