|
@@ -224,13 +224,11 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
|
|
|
switch (asic_type) {
|
|
|
case CHIP_STONEY:
|
|
|
dmadscr[i].xfer_val |=
|
|
|
- BIT(22) |
|
|
|
(ACP_DMA_ATTR_SHARED_MEM_TO_DAGB_GARLIC << 16) |
|
|
|
(size / 2);
|
|
|
break;
|
|
|
default:
|
|
|
dmadscr[i].xfer_val |=
|
|
|
- BIT(22) |
|
|
|
(ACP_DMA_ATTR_SHAREDMEM_TO_DAGB_ONION << 16) |
|
|
|
(size / 2);
|
|
|
}
|
|
@@ -322,22 +320,87 @@ static void config_acp_dma(void __iomem *acp_mmio,
|
|
|
struct audio_substream_data *rtd,
|
|
|
u32 asic_type)
|
|
|
{
|
|
|
+ u16 ch_acp_sysmem, ch_acp_i2s;
|
|
|
+
|
|
|
acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages,
|
|
|
rtd->pte_offset);
|
|
|
+
|
|
|
+ if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
+ ch_acp_sysmem = rtd->ch1;
|
|
|
+ ch_acp_i2s = rtd->ch2;
|
|
|
+ } else {
|
|
|
+ ch_acp_i2s = rtd->ch1;
|
|
|
+ ch_acp_sysmem = rtd->ch2;
|
|
|
+ }
|
|
|
/* Configure System memory <-> ACP SRAM DMA descriptors */
|
|
|
set_acp_sysmem_dma_descriptors(acp_mmio, rtd->size,
|
|
|
rtd->direction, rtd->pte_offset,
|
|
|
- rtd->ch1, rtd->sram_bank,
|
|
|
+ ch_acp_sysmem, rtd->sram_bank,
|
|
|
rtd->dma_dscr_idx_1, asic_type);
|
|
|
/* Configure ACP SRAM <-> I2S DMA descriptors */
|
|
|
set_acp_to_i2s_dma_descriptors(acp_mmio, rtd->size,
|
|
|
rtd->direction, rtd->sram_bank,
|
|
|
- rtd->destination, rtd->ch2,
|
|
|
+ rtd->destination, ch_acp_i2s,
|
|
|
rtd->dma_dscr_idx_2, asic_type);
|
|
|
}
|
|
|
|
|
|
+static void acp_dma_cap_channel_enable(void __iomem *acp_mmio,
|
|
|
+ u16 cap_channel)
|
|
|
+{
|
|
|
+ u32 val, ch_reg, imr_reg, res_reg;
|
|
|
+
|
|
|
+ switch (cap_channel) {
|
|
|
+ case CAP_CHANNEL1:
|
|
|
+ ch_reg = mmACP_I2SMICSP_RER1;
|
|
|
+ res_reg = mmACP_I2SMICSP_RCR1;
|
|
|
+ imr_reg = mmACP_I2SMICSP_IMR1;
|
|
|
+ break;
|
|
|
+ case CAP_CHANNEL0:
|
|
|
+ default:
|
|
|
+ ch_reg = mmACP_I2SMICSP_RER0;
|
|
|
+ res_reg = mmACP_I2SMICSP_RCR0;
|
|
|
+ imr_reg = mmACP_I2SMICSP_IMR0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ val = acp_reg_read(acp_mmio,
|
|
|
+ mmACP_I2S_16BIT_RESOLUTION_EN);
|
|
|
+ if (val & ACP_I2S_MIC_16BIT_RESOLUTION_EN) {
|
|
|
+ acp_reg_write(0x0, acp_mmio, ch_reg);
|
|
|
+ /* Set 16bit resolution on capture */
|
|
|
+ acp_reg_write(0x2, acp_mmio, res_reg);
|
|
|
+ }
|
|
|
+ val = acp_reg_read(acp_mmio, imr_reg);
|
|
|
+ val &= ~ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK;
|
|
|
+ val &= ~ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK;
|
|
|
+ acp_reg_write(val, acp_mmio, imr_reg);
|
|
|
+ acp_reg_write(0x1, acp_mmio, ch_reg);
|
|
|
+}
|
|
|
+
|
|
|
+static void acp_dma_cap_channel_disable(void __iomem *acp_mmio,
|
|
|
+ u16 cap_channel)
|
|
|
+{
|
|
|
+ u32 val, ch_reg, imr_reg;
|
|
|
+
|
|
|
+ switch (cap_channel) {
|
|
|
+ case CAP_CHANNEL1:
|
|
|
+ imr_reg = mmACP_I2SMICSP_IMR1;
|
|
|
+ ch_reg = mmACP_I2SMICSP_RER1;
|
|
|
+ break;
|
|
|
+ case CAP_CHANNEL0:
|
|
|
+ default:
|
|
|
+ imr_reg = mmACP_I2SMICSP_IMR0;
|
|
|
+ ch_reg = mmACP_I2SMICSP_RER0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ val = acp_reg_read(acp_mmio, imr_reg);
|
|
|
+ val |= ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK;
|
|
|
+ val |= ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK;
|
|
|
+ acp_reg_write(val, acp_mmio, imr_reg);
|
|
|
+ acp_reg_write(0x0, acp_mmio, ch_reg);
|
|
|
+}
|
|
|
+
|
|
|
/* Start a given DMA channel transfer */
|
|
|
-static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
|
|
|
+static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num, bool is_circular)
|
|
|
{
|
|
|
u32 dma_ctrl;
|
|
|
|
|
@@ -356,10 +419,8 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
|
|
|
|
|
|
switch (ch_num) {
|
|
|
case ACP_TO_I2S_DMA_CH_NUM:
|
|
|
- case ACP_TO_SYSRAM_CH_NUM:
|
|
|
case I2S_TO_ACP_DMA_CH_NUM:
|
|
|
case ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM:
|
|
|
- case ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM:
|
|
|
case I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM:
|
|
|
dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
|
|
|
break;
|
|
@@ -368,8 +429,11 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- /* circular for both DMA channel */
|
|
|
- dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
|
|
|
+ /* enable for ACP to SRAM DMA channel */
|
|
|
+ if (is_circular == true)
|
|
|
+ dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
|
|
|
+ else
|
|
|
+ dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
|
|
|
|
|
|
acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
|
|
|
}
|
|
@@ -613,6 +677,7 @@ static int acp_deinit(void __iomem *acp_mmio)
|
|
|
/* ACP DMA irq handler routine for playback, capture usecases */
|
|
|
static irqreturn_t dma_irq_handler(int irq, void *arg)
|
|
|
{
|
|
|
+ u16 dscr_idx;
|
|
|
u32 intr_flag, ext_intr_status;
|
|
|
struct audio_drv_data *irq_data;
|
|
|
void __iomem *acp_mmio;
|
|
@@ -644,32 +709,39 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
|
|
|
|
|
|
if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) {
|
|
|
valid_irq = true;
|
|
|
+ if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_14) ==
|
|
|
+ CAPTURE_START_DMA_DESCR_CH15)
|
|
|
+ dscr_idx = CAPTURE_END_DMA_DESCR_CH14;
|
|
|
+ else
|
|
|
+ dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
|
|
|
+ config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx,
|
|
|
+ 1, 0);
|
|
|
+ acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false);
|
|
|
+
|
|
|
snd_pcm_period_elapsed(irq_data->capture_i2ssp_stream);
|
|
|
acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16,
|
|
|
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
|
|
|
}
|
|
|
|
|
|
- if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
|
|
|
- valid_irq = true;
|
|
|
- acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
|
|
|
- acp_mmio, mmACP_EXTERNAL_INTR_STAT);
|
|
|
- }
|
|
|
-
|
|
|
if ((intr_flag & BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) != 0) {
|
|
|
valid_irq = true;
|
|
|
+ if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_10) ==
|
|
|
+ CAPTURE_START_DMA_DESCR_CH11)
|
|
|
+ dscr_idx = CAPTURE_END_DMA_DESCR_CH10;
|
|
|
+ else
|
|
|
+ dscr_idx = CAPTURE_START_DMA_DESCR_CH10;
|
|
|
+ config_acp_dma_channel(acp_mmio,
|
|
|
+ ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM,
|
|
|
+ dscr_idx, 1, 0);
|
|
|
+ acp_dma_start(acp_mmio, ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM,
|
|
|
+ false);
|
|
|
+
|
|
|
snd_pcm_period_elapsed(irq_data->capture_i2sbt_stream);
|
|
|
acp_reg_write((intr_flag &
|
|
|
BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) << 16,
|
|
|
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
|
|
|
}
|
|
|
|
|
|
- if ((intr_flag & BIT(ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM)) != 0) {
|
|
|
- valid_irq = true;
|
|
|
- acp_reg_write((intr_flag &
|
|
|
- BIT(ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM)) << 16,
|
|
|
- acp_mmio, mmACP_EXTERNAL_INTR_STAT);
|
|
|
- }
|
|
|
-
|
|
|
if (valid_irq)
|
|
|
return IRQ_HANDLED;
|
|
|
else
|
|
@@ -773,8 +845,10 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
|
|
if (WARN_ON(!rtd))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (pinfo)
|
|
|
+ if (pinfo) {
|
|
|
rtd->i2s_instance = pinfo->i2s_instance;
|
|
|
+ rtd->capture_channel = pinfo->capture_channel;
|
|
|
+ }
|
|
|
if (adata->asic_type == CHIP_STONEY) {
|
|
|
val = acp_reg_read(adata->acp_mmio,
|
|
|
mmACP_I2S_16BIT_RESOLUTION_EN);
|
|
@@ -842,8 +916,8 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
|
|
switch (rtd->i2s_instance) {
|
|
|
case I2S_BT_INSTANCE:
|
|
|
rtd->pte_offset = ACP_ST_BT_CAPTURE_PTE_OFFSET;
|
|
|
- rtd->ch1 = ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM;
|
|
|
- rtd->ch2 = I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM;
|
|
|
+ rtd->ch1 = I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM;
|
|
|
+ rtd->ch2 = ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM;
|
|
|
rtd->sram_bank = ACP_SRAM_BANK_4_ADDRESS;
|
|
|
rtd->destination = FROM_BLUETOOTH;
|
|
|
rtd->dma_dscr_idx_1 = CAPTURE_START_DMA_DESCR_CH10;
|
|
@@ -852,13 +926,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
|
|
mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH;
|
|
|
rtd->byte_cnt_low_reg_offset =
|
|
|
mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW;
|
|
|
+ rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_11;
|
|
|
adata->capture_i2sbt_stream = substream;
|
|
|
break;
|
|
|
case I2S_SP_INSTANCE:
|
|
|
default:
|
|
|
rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET;
|
|
|
- rtd->ch1 = ACP_TO_SYSRAM_CH_NUM;
|
|
|
- rtd->ch2 = I2S_TO_ACP_DMA_CH_NUM;
|
|
|
+ rtd->ch1 = I2S_TO_ACP_DMA_CH_NUM;
|
|
|
+ rtd->ch2 = ACP_TO_SYSRAM_CH_NUM;
|
|
|
switch (adata->asic_type) {
|
|
|
case CHIP_STONEY:
|
|
|
rtd->pte_offset = ACP_ST_CAPTURE_PTE_OFFSET;
|
|
@@ -875,6 +950,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
|
|
mmACP_I2S_RECEIVED_BYTE_CNT_HIGH;
|
|
|
rtd->byte_cnt_low_reg_offset =
|
|
|
mmACP_I2S_RECEIVED_BYTE_CNT_LOW;
|
|
|
+ rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_15;
|
|
|
adata->capture_i2ssp_stream = substream;
|
|
|
}
|
|
|
}
|
|
@@ -928,6 +1004,8 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
|
|
|
u32 buffersize;
|
|
|
u32 pos = 0;
|
|
|
u64 bytescount = 0;
|
|
|
+ u16 dscr;
|
|
|
+ u32 period_bytes, delay;
|
|
|
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
struct audio_substream_data *rtd = runtime->private_data;
|
|
@@ -935,12 +1013,25 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
|
|
|
if (!rtd)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- buffersize = frames_to_bytes(runtime, runtime->buffer_size);
|
|
|
- bytescount = acp_get_byte_count(rtd);
|
|
|
-
|
|
|
- if (bytescount > rtd->bytescount)
|
|
|
- bytescount -= rtd->bytescount;
|
|
|
- pos = do_div(bytescount, buffersize);
|
|
|
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
|
|
+ period_bytes = frames_to_bytes(runtime, runtime->period_size);
|
|
|
+ dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr);
|
|
|
+ if (dscr == rtd->dma_dscr_idx_1)
|
|
|
+ pos = period_bytes;
|
|
|
+ else
|
|
|
+ pos = 0;
|
|
|
+ bytescount = acp_get_byte_count(rtd);
|
|
|
+ if (bytescount > rtd->bytescount)
|
|
|
+ bytescount -= rtd->bytescount;
|
|
|
+ delay = do_div(bytescount, period_bytes);
|
|
|
+ runtime->delay = bytes_to_frames(runtime, delay);
|
|
|
+ } else {
|
|
|
+ buffersize = frames_to_bytes(runtime, runtime->buffer_size);
|
|
|
+ bytescount = acp_get_byte_count(rtd);
|
|
|
+ if (bytescount > rtd->bytescount)
|
|
|
+ bytescount -= rtd->bytescount;
|
|
|
+ pos = do_div(bytescount, buffersize);
|
|
|
+ }
|
|
|
return bytes_to_frames(runtime, pos);
|
|
|
}
|
|
|
|
|
@@ -954,16 +1045,24 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
|
|
|
{
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
struct audio_substream_data *rtd = runtime->private_data;
|
|
|
+ u16 ch_acp_sysmem, ch_acp_i2s;
|
|
|
|
|
|
if (!rtd)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
+ ch_acp_sysmem = rtd->ch1;
|
|
|
+ ch_acp_i2s = rtd->ch2;
|
|
|
+ } else {
|
|
|
+ ch_acp_i2s = rtd->ch1;
|
|
|
+ ch_acp_sysmem = rtd->ch2;
|
|
|
+ }
|
|
|
config_acp_dma_channel(rtd->acp_mmio,
|
|
|
- rtd->ch1,
|
|
|
+ ch_acp_sysmem,
|
|
|
rtd->dma_dscr_idx_1,
|
|
|
NUM_DSCRS_PER_CHANNEL, 0);
|
|
|
config_acp_dma_channel(rtd->acp_mmio,
|
|
|
- rtd->ch2,
|
|
|
+ ch_acp_i2s,
|
|
|
rtd->dma_dscr_idx_2,
|
|
|
NUM_DSCRS_PER_CHANNEL, 0);
|
|
|
return 0;
|
|
@@ -972,7 +1071,6 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
|
|
|
static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
|
|
{
|
|
|
int ret;
|
|
|
- u64 bytescount = 0;
|
|
|
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
struct audio_substream_data *rtd = runtime->private_data;
|
|
@@ -983,37 +1081,32 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
|
|
case SNDRV_PCM_TRIGGER_START:
|
|
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
|
case SNDRV_PCM_TRIGGER_RESUME:
|
|
|
- bytescount = acp_get_byte_count(rtd);
|
|
|
- if (rtd->bytescount == 0)
|
|
|
- rtd->bytescount = bytescount;
|
|
|
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
- acp_dma_start(rtd->acp_mmio, rtd->ch1);
|
|
|
- acp_dma_start(rtd->acp_mmio, rtd->ch2);
|
|
|
+ rtd->bytescount = acp_get_byte_count(rtd);
|
|
|
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
|
|
+ if (rtd->capture_channel == CAP_CHANNEL0) {
|
|
|
+ acp_dma_cap_channel_disable(rtd->acp_mmio,
|
|
|
+ CAP_CHANNEL1);
|
|
|
+ acp_dma_cap_channel_enable(rtd->acp_mmio,
|
|
|
+ CAP_CHANNEL0);
|
|
|
+ }
|
|
|
+ if (rtd->capture_channel == CAP_CHANNEL1) {
|
|
|
+ acp_dma_cap_channel_disable(rtd->acp_mmio,
|
|
|
+ CAP_CHANNEL0);
|
|
|
+ acp_dma_cap_channel_enable(rtd->acp_mmio,
|
|
|
+ CAP_CHANNEL1);
|
|
|
+ }
|
|
|
+ acp_dma_start(rtd->acp_mmio, rtd->ch1, true);
|
|
|
} else {
|
|
|
- acp_dma_start(rtd->acp_mmio, rtd->ch2);
|
|
|
- acp_dma_start(rtd->acp_mmio, rtd->ch1);
|
|
|
+ acp_dma_start(rtd->acp_mmio, rtd->ch1, true);
|
|
|
+ acp_dma_start(rtd->acp_mmio, rtd->ch2, true);
|
|
|
}
|
|
|
ret = 0;
|
|
|
break;
|
|
|
case SNDRV_PCM_TRIGGER_STOP:
|
|
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
|
- /* For playback, non circular dma should be stopped first
|
|
|
- * i.e Sysram to acp dma transfer channel(rtd->ch1) should be
|
|
|
- * stopped before stopping cirular dma which is acp sram to i2s
|
|
|
- * fifo dma transfer channel(rtd->ch2). Where as in Capture
|
|
|
- * scenario, i2s fifo to acp sram dma channel(rtd->ch2) stopped
|
|
|
- * first before stopping acp sram to sysram which is circular
|
|
|
- * dma(rtd->ch1).
|
|
|
- */
|
|
|
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
- acp_dma_stop(rtd->acp_mmio, rtd->ch1);
|
|
|
- ret = acp_dma_stop(rtd->acp_mmio, rtd->ch2);
|
|
|
- } else {
|
|
|
- acp_dma_stop(rtd->acp_mmio, rtd->ch2);
|
|
|
- ret = acp_dma_stop(rtd->acp_mmio, rtd->ch1);
|
|
|
- }
|
|
|
- rtd->bytescount = 0;
|
|
|
+ acp_dma_stop(rtd->acp_mmio, rtd->ch2);
|
|
|
+ ret = acp_dma_stop(rtd->acp_mmio, rtd->ch1);
|
|
|
break;
|
|
|
default:
|
|
|
ret = -EINVAL;
|