[alsa-devel] [PATCH 05/12] drm/amd: modify ACP DMA buffer position update logic (v2)
Alex Deucher
alexdeucher at gmail.com
Thu Aug 6 16:25:05 CEST 2015
From: Maruthi Srinivas Bayyavarapu <Maruthi.Bayyavarapu at amd.com>
The following are design changes for ACP DMA :
1. For capture usecase, DMA Interrupt on Complete is added for
ACP_TO_SYSRAM_CH_NUM DMA channel
2. For playback usecase, the destination for DMA descriptors is
reversed.
3. Finally, modified DMA buffer position update logic as per above
changes.
v2: minor code cleanups
Signed-off-by: Maruthi Bayyavarapu <maruthi.bayyavarapu at amd.com>
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
Reviewed-by: Murali Krishna Vemuri <murali-krishna.vemuri at amd.com>
Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
---
drivers/gpu/drm/amd/acp/acp_hw.c | 156 ++++++++++++++++++++++-----------------
drivers/gpu/drm/amd/acp/acp_hw.h | 19 ++---
2 files changed, 93 insertions(+), 82 deletions(-)
diff --git a/drivers/gpu/drm/amd/acp/acp_hw.c b/drivers/gpu/drm/amd/acp/acp_hw.c
index 069fea7..34bb0fe 100644
--- a/drivers/gpu/drm/amd/acp/acp_hw.c
+++ b/drivers/gpu/drm/amd/acp/acp_hw.c
@@ -40,7 +40,7 @@
#include <linux/delay.h>
#include <linux/errno.h>
-#define VISLANDS30_IV_SRCID_ACP 0x000000a2 // 162
+#define VISLANDS30_IV_SRCID_ACP 0x000000a2
#include "acp_gfx_if.h"
#include "acp_hw.h"
@@ -91,10 +91,9 @@ static void config_acp_dma_channel(struct amd_acp_device *acp_dev, u8 ch_num,
/* Initialize the dma descriptors location in SRAM and page size */
-static void acp_dma_descr_init(struct amd_acp_device *acp_dev)
+static void acp_dma_descr_init(struct amd_acp_private *acp_prv)
{
u32 sram_pte_offset = 0;
- struct amd_acp_private *acp_prv = (struct amd_acp_private *)acp_dev;
/* SRAM starts at 0x04000000. From that offset one page (4KB) left for
* filling DMA descriptors.sram_pte_offset = 0x04001000 , used for
@@ -146,10 +145,11 @@ static void config_dma_descriptor_in_sram(struct amd_acp_device *acp_dev,
/* Initialize the DMA descriptor information */
static void set_acp_sysmem_dma_descriptors(struct amd_acp_device *acp_dev,
- u32 size, int direction, u32 pte_offset)
+ u32 size, int direction,
+ u32 pte_offset)
{
- u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
u16 num_descr;
+ u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
acp_dma_dscr_transfer_t dmadscr[2];
num_descr = 2;
@@ -157,43 +157,45 @@ static void set_acp_sysmem_dma_descriptors(struct amd_acp_device *acp_dev,
dmadscr[0].size_xfer_dir.val = (u32) 0x0;
if (direction == STREAM_PLAYBACK) {
dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
- dmadscr[0].dest = ACP_SHARED_RAM_BANK_38_ADDRESS;
+ dmadscr[0].dest = ACP_SHARED_RAM_BANK_38_ADDRESS + (size / 2);
dmadscr[0].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
(pte_offset * PAGE_SIZE_4K);
dmadscr[0].size_xfer_dir.s.trans_direction =
ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM;
- } else if (direction == STREAM_CAPTURE) {
+ dmadscr[0].size_xfer_dir.s.size = (size / 2);
+ dmadscr[0].size_xfer_dir.s.ioc = (u32) 0x0;
+ } else {
dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
dmadscr[0].src = ACP_SHARED_RAM_BANK_47_ADDRESS;
dmadscr[0].dest = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
(pte_offset * PAGE_SIZE_4K);
dmadscr[0].size_xfer_dir.s.trans_direction =
ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION;
+ dmadscr[0].size_xfer_dir.s.size = size / 2;
+ dmadscr[0].size_xfer_dir.s.ioc = (u32) 0x1;
}
- /* allot 1 period size per descriptor = total size (size) /2
- * => params_buffer_bytes(params)/params_periods(params);
- */
- dmadscr[0].size_xfer_dir.s.size = size / 2;
-
- dmadscr[0].size_xfer_dir.s.ioc = (u32) 0x0;
-
config_dma_descriptor_in_sram(acp_dev, dma_dscr_idx, &dmadscr[0]);
dmadscr[1].size_xfer_dir.val = (u32) 0x0;
- dmadscr[1].dest = dmadscr[0].dest + dmadscr[0].size_xfer_dir.s.size;
- dmadscr[1].src = dmadscr[0].src + dmadscr[0].size_xfer_dir.s.size;
- dmadscr[1].size_xfer_dir.s.size = dmadscr[0].size_xfer_dir.s.size;
- dmadscr[1].size_xfer_dir.s.ioc = (u32) 0x0;
-
if (direction == STREAM_PLAYBACK) {
dma_dscr_idx = PLAYBACK_END_DMA_DESCR_CH12;
+ dmadscr[1].dest = ACP_SHARED_RAM_BANK_38_ADDRESS;
+ dmadscr[1].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
+ (pte_offset * PAGE_SIZE_4K) + (size / 2);
dmadscr[1].size_xfer_dir.s.trans_direction =
ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM;
- } else if (direction == STREAM_CAPTURE) {
+ dmadscr[1].size_xfer_dir.s.size = (size / 2);
+ dmadscr[1].size_xfer_dir.s.ioc = (u32) 0x0;
+ } else {
dma_dscr_idx = CAPTURE_END_DMA_DESCR_CH14;
dmadscr[1].size_xfer_dir.s.trans_direction =
ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION;
+ dmadscr[1].size_xfer_dir.val = (u32) 0x0;
+ dmadscr[1].dest = dmadscr[0].dest + (size / 2);
+ dmadscr[1].src = dmadscr[0].src + (size / 2);
+ dmadscr[1].size_xfer_dir.s.size = (size / 2);
+ dmadscr[1].size_xfer_dir.s.ioc = (u32) 0x1;
}
config_dma_descriptor_in_sram(acp_dev, dma_dscr_idx, &dmadscr[1]);
@@ -204,7 +206,7 @@ static void set_acp_sysmem_dma_descriptors(struct amd_acp_device *acp_dev,
config_acp_dma_channel(acp_dev, SYSRAM_TO_ACP_CH_NUM,
dma_dscr_idx, num_descr,
ACP_DMA_PRIORITY_LEVEL_NORMAL);
- } else if (direction == STREAM_CAPTURE) {
+ } else {
/* starting descriptor for this channel */
dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
config_acp_dma_channel(acp_dev, ACP_TO_SYSRAM_CH_NUM,
@@ -228,34 +230,38 @@ static void set_acp_to_i2s_dma_descriptors(struct amd_acp_device *acp_dev,
* of data
*/
dmadscr[0].size_xfer_dir.val = (u32) 0x0;
- dmadscr[0].size_xfer_dir.s.size = (size / 2);
- dmadscr[0].size_xfer_dir.s.ioc = (u32) 0x1;
if (direction == STREAM_PLAYBACK) {
dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13;
dmadscr[0].src = ACP_SHARED_RAM_BANK_38_ADDRESS;
dmadscr[0].size_xfer_dir.s.trans_direction = TO_ACP_I2S_1;
- } else if (direction == STREAM_CAPTURE) {
+ dmadscr[0].size_xfer_dir.s.size = (size / 2);
+ dmadscr[0].size_xfer_dir.s.ioc = (u32) 0x1;
+ } else {
dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15;
dmadscr[0].dest = ACP_SHARED_RAM_BANK_47_ADDRESS;
- dmadscr[0].size_xfer_dir.s.trans_direction = 0xa;
+ dmadscr[0].size_xfer_dir.s.trans_direction = FROM_ACP_I2S_1;
+ dmadscr[0].size_xfer_dir.s.size = (size / 2);
+ dmadscr[0].size_xfer_dir.s.ioc = (u32) 0x1;
}
+
config_dma_descriptor_in_sram(acp_dev, dma_dscr_idx, &dmadscr[0]);
dmadscr[1].size_xfer_dir.val = (u32) 0x0;
- dmadscr[1].size_xfer_dir.s.size = (size / 2);
- dmadscr[1].size_xfer_dir.s.ioc = (u32) 0x1;
if (direction == STREAM_PLAYBACK) {
dma_dscr_idx = PLAYBACK_END_DMA_DESCR_CH13;
- dmadscr[1].src = dmadscr[0].src +
- dmadscr[0].size_xfer_dir.s.size;
+ dmadscr[1].src = dmadscr[0].src + (size / 2);
dmadscr[1].size_xfer_dir.s.trans_direction = TO_ACP_I2S_1;
+ dmadscr[1].size_xfer_dir.s.size = (size / 2);
+ dmadscr[1].size_xfer_dir.s.ioc = (u32) 0x1;
- } else if (direction == STREAM_CAPTURE) {
+ } else {
dma_dscr_idx = CAPTURE_END_DMA_DESCR_CH15;
- dmadscr[1].dest = dmadscr[0].dest +
- dmadscr[0].size_xfer_dir.s.size;
- dmadscr[1].size_xfer_dir.s.trans_direction = 0xa;
+ dmadscr[1].dest = dmadscr[0].dest + (size / 2);
+ dmadscr[1].size_xfer_dir.s.trans_direction = FROM_ACP_I2S_1;
+ dmadscr[1].size_xfer_dir.s.size = (size / 2);
+ dmadscr[1].size_xfer_dir.s.ioc = (u32) 0x1;
}
+
config_dma_descriptor_in_sram(acp_dev, dma_dscr_idx, &dmadscr[1]);
/* Configure the DMA channel with the above descriptore */
@@ -265,7 +271,7 @@ static void set_acp_to_i2s_dma_descriptors(struct amd_acp_device *acp_dev,
config_acp_dma_channel(acp_dev, ACP_TO_I2S_DMA_CH_NUM,
dma_dscr_idx, num_descr,
ACP_DMA_PRIORITY_LEVEL_NORMAL);
- } else if (direction == STREAM_CAPTURE) {
+ } else {
/* starting descriptor for this channel */
dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15;
config_acp_dma_channel(acp_dev, I2S_TO_ACP_DMA_CH_NUM,
@@ -284,8 +290,8 @@ static u16 get_dscr_idx(struct amd_acp_device *acp_dev, int direction)
dscr_idx = cgs_read_register(acp_prv->cgs_device,
mmACP_DMA_CUR_DSCR_13);
dscr_idx = (dscr_idx == PLAYBACK_START_DMA_DESCR_CH13) ?
- PLAYBACK_END_DMA_DESCR_CH12 :
- PLAYBACK_START_DMA_DESCR_CH12;
+ PLAYBACK_START_DMA_DESCR_CH12 :
+ PLAYBACK_END_DMA_DESCR_CH12;
} else {
dscr_idx = cgs_read_register(acp_prv->cgs_device,
mmACP_DMA_CUR_DSCR_15);
@@ -470,7 +476,7 @@ static void configure_i2s_stream(struct amd_acp_device *acp_dev,
/*Enable Transmit */
cgs_write_register(acp_prv->cgs_device,
(mmACP_I2SSP_TER0 + (0x10 *
- i2s_config->ch_reg)), 1);
+ i2s_config->ch_reg)), 1);
} else {
/* Receive configuration register for data width */
cgs_write_register(acp_prv->cgs_device,
@@ -479,11 +485,11 @@ static void configure_i2s_stream(struct amd_acp_device *acp_dev,
i2s_config->xfer_resolution);
cgs_write_register(acp_prv->cgs_device,
(mmACP_I2SMICSP_RFCR0 + (0x10 *
- i2s_config->ch_reg)), 0x07);
+ i2s_config->ch_reg)), 0x07);
/*Read interrupt mask register */
i2s_config->irq = cgs_read_register(acp_prv->cgs_device,
(mmACP_I2SMICSP_IMR0 +
- (0x10 * i2s_config->ch_reg)));
+ (0x10 * i2s_config->ch_reg)));
/* TX FIFO Overrun,Empty interrupts */
cgs_write_register(acp_prv->cgs_device,
@@ -493,8 +499,7 @@ static void configure_i2s_stream(struct amd_acp_device *acp_dev,
/*Enable Receive */
cgs_write_register(acp_prv->cgs_device,
(mmACP_I2SMICSP_RER0 + (0x10 *
- i2s_config->ch_reg)), 1);
-
+ i2s_config->ch_reg)), 1);
}
}
@@ -545,16 +550,18 @@ static int acp_dma_start(struct amd_acp_device *acp_dev,
dma_ctrl |= ACP_DMA_CNTL_0__DMAChRun_MASK;
if ((ch_num == ACP_TO_I2S_DMA_CH_NUM) ||
+ (ch_num == ACP_TO_SYSRAM_CH_NUM) ||
(ch_num == I2S_TO_ACP_DMA_CH_NUM)) {
dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
- cgs_irq_get(acp_prv->cgs_device, VISLANDS30_IV_SRCID_ACP, 0);
} else {
dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
}
/* enable for ACP SRAM to/from I2S DMA channel */
- if (is_circular == true)
+ if (is_circular == true) {
dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+ cgs_irq_get(acp_prv->cgs_device, VISLANDS30_IV_SRCID_ACP, 0);
+ }
else
dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
@@ -562,7 +569,6 @@ static int acp_dma_start(struct amd_acp_device *acp_dev,
dma_ctrl);
status = STATUS_SUCCESS;
-
return status;
}
@@ -614,7 +620,8 @@ static int acp_dma_stop(struct amd_acp_device *acp_dev, u8 ch_num)
dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRst_MASK;
cgs_write_register(acp_prv->cgs_device,
- (mmACP_DMA_CNTL_0 + ch_num), dma_ctrl);
+ (mmACP_DMA_CNTL_0 + ch_num),
+ dma_ctrl);
status = STATUS_SUCCESS;
break;
}
@@ -631,47 +638,58 @@ static int acp_dma_stop(struct amd_acp_device *acp_dev, u8 ch_num)
static int dma_irq_handler(void *prv_data)
{
- u16 play_intr, capture_intr;
+ u16 play_acp_i2s_intr, cap_i2s_acp_intr, cap_acp_sysram_intr;
u16 dscr_idx, intr_flag;
+ u32 ext_intr_status;
int priority_level = 0x0;
int dma_transfer_status = STATUS_UNSUCCESSFUL;
struct acp_irq_prv *idata = prv_data;
struct amd_acp_device *acp_dev = idata->acp_dev;
+ struct amd_acp_private *acp_prv = (struct amd_acp_private *)acp_dev;
intr_flag = acp_get_intr_flag(acp_dev);
- play_intr = (intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM));
- capture_intr = (intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM));
- if (!play_intr && !capture_intr) {
+ play_acp_i2s_intr = (intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM));
+ cap_i2s_acp_intr = (intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM));
+ cap_acp_sysram_intr = (intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM));
+
+ if (!play_acp_i2s_intr && !cap_i2s_acp_intr && !cap_acp_sysram_intr) {
/* We registered for DMA Interrupt-On-Complete interrupts only.
- * If we hit here, just return. */
- pr_info("ACP:irq_handler: play_intr && capture_intr = false\n");
+ * If we hit here, log, acknowledge it and return. */
+ ext_intr_status = cgs_read_register(acp_prv->cgs_device,
+ mmACP_EXTERNAL_INTR_STAT);
+ pr_info("ACP: Not a DMA IOC irq: %x\n", ext_intr_status);
return 0;
}
- if (play_intr) {
+ if (play_acp_i2s_intr) {
dscr_idx = get_dscr_idx(acp_dev, STREAM_PLAYBACK);
config_acp_dma_channel(acp_dev, SYSRAM_TO_ACP_CH_NUM, dscr_idx,
1, priority_level);
dma_transfer_status = acp_dma_start(acp_dev,
SYSRAM_TO_ACP_CH_NUM,
false);
- idata->set_elapsed(idata->dev, play_intr, capture_intr);
+ idata->set_elapsed(idata->dev, 1, 0);
acp_ext_stat_clear_dmaioc(acp_dev, ACP_TO_I2S_DMA_CH_NUM);
}
- if (capture_intr) {
+ if (cap_i2s_acp_intr) {
dscr_idx = get_dscr_idx(acp_dev, STREAM_CAPTURE);
config_acp_dma_channel(acp_dev, ACP_TO_SYSRAM_CH_NUM, dscr_idx,
1, priority_level);
dma_transfer_status = acp_dma_start(acp_dev,
ACP_TO_SYSRAM_CH_NUM,
false);
- idata->set_elapsed(idata->dev, play_intr, capture_intr);
acp_ext_stat_clear_dmaioc(acp_dev, I2S_TO_ACP_DMA_CH_NUM);
}
+
+ if (cap_acp_sysram_intr) {
+ idata->set_elapsed(idata->dev, 0, 1);
+ acp_ext_stat_clear_dmaioc(acp_dev, ACP_TO_SYSRAM_CH_NUM);
+ }
+
return 0;
}
@@ -737,7 +755,7 @@ static int acp_hw_init(struct amd_acp_device *acp_dev, void *iprv)
cgs_write_register(acp_prv->cgs_device, mmACP_AXI2DAGB_GARLIC_CNTL,
GARLIC_CNTL_DEFAULT);
- acp_dma_descr_init(acp_dev);
+ acp_dma_descr_init(acp_prv);
/* DMA DSCR BASE ADDRESS IN SRAM */
cgs_write_register(acp_prv->cgs_device, mmACP_DMA_DESC_BASE_ADDR,
@@ -811,24 +829,24 @@ static u32 acp_update_dma_pointer(struct amd_acp_device *acp_dev, int direction,
if (direction == STREAM_PLAYBACK) {
dscr = cgs_read_register(acp_prv->cgs_device,
mmACP_DMA_CUR_DSCR_13);
- pos = cgs_read_register(acp_prv->cgs_device,
- mmACP_DMA_CUR_TRANS_CNT_13);
- /* dscr = either 2 or 3 only */
- mul = (dscr == PLAYBACK_START_DMA_DESCR_CH13) ? 1 : 0;
- pos = (mul * period_size) + pos;
- } else if (direction == STREAM_CAPTURE) {
- dscr = cgs_read_register(acp_prv->cgs_device,
- mmACP_DMA_CUR_DSCR_15);
- pos = cgs_read_register(acp_prv->cgs_device,
- mmACP_DMA_CUR_TRANS_CNT_15);
+
+ mul = (dscr == PLAYBACK_START_DMA_DESCR_CH13) ? 0 : 1;
+ pos = (mul * period_size);
+
+ } else {
dma_config = cgs_read_register(acp_prv->cgs_device,
mmACP_DMA_CNTL_14);
if (dma_config != 0) {
- mul = (dscr == CAPTURE_START_DMA_DESCR_CH15) ? 1 : 0;
- pos = (mul * period_size) + pos;
+ dscr = cgs_read_register(acp_prv->cgs_device,
+ mmACP_DMA_CUR_DSCR_14);
+ mul = (dscr == CAPTURE_START_DMA_DESCR_CH14) ? 1 : 2;
+ pos = (mul * period_size);
}
- }
+ if (pos >= (2 * period_size))
+ pos = 0;
+
+ }
return pos;
}
diff --git a/drivers/gpu/drm/amd/acp/acp_hw.h b/drivers/gpu/drm/amd/acp/acp_hw.h
index 384d97d..5e7e225 100644
--- a/drivers/gpu/drm/amd/acp/acp_hw.h
+++ b/drivers/gpu/drm/amd/acp/acp_hw.h
@@ -22,7 +22,7 @@
#define ACP_SHARED_RAM_BANK_38_ADDRESS 0x404A000
/* Capture SRAM address (as a source in dma descriptor) */
-#define ACP_SHARED_RAM_BANK_47_ADDRESS 0x405C000
+#define ACP_SHARED_RAM_BANK_47_ADDRESS 0x4054000
#define ACP_DMA_RESET_TIME 10000
#define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF
@@ -35,6 +35,11 @@
#define ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS 0x00000000
#define ACP_INTERNAL_APERTURE_WINDOW_4_ADDRESS 0x01800000
+#define TO_ACP_I2S_1 0x2
+#define TO_ACP_I2S_2 0x4
+#define FROM_ACP_I2S_1 0xa
+#define FROM_ACP_I2S_2 0xb
+
enum {
STREAM_PLAYBACK = 0,
STREAM_CAPTURE,
@@ -42,18 +47,6 @@ enum {
};
enum {
- To_DAGB_O = 0x0,
- To_DAGB_G,
- TO_ACP_I2S_1,
- TO_BLUETOOTH,
- TO_ACP_I2S_2,
- FROM_DAGB_O,
- FROM_DAGB_G,
- FROM_ACP_I2S_1,
- FROM_ACP_I2S_2
-};
-
-enum {
ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION = 0x0,
ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC = 0x1,
ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM = 0x8,
--
1.8.3.1
More information about the Alsa-devel
mailing list