On 6/6/2018 2:06 PM, Ranjani Sridharan wrote:
On Wed, 2018-06-06 at 10:23 +0800, rander.wang wrote:
On 6/6/2018 3:12 AM, Ranjani Sridharan wrote:
On Tue, 2018-06-05 at 16:14 +0800, rander.wang wrote:
On 6/5/2018 12:23 PM, Ranjani Sridharan wrote:
This patch introduces a new API for procuring DMAC for various user based on the type of DMAC, copy direction and other flags for share/exclusive access. It defines the necessary DMAC user types, copy direction and the flags to suuport the new API.It also adds two new members to dma_plat_data to differentiate the DMAC based on usage and copy direction.
Finally, it also contains the platform specific implementation of the new dma_get() API.
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel .com
src/include/sof/dma.h | 26 ++++++++++++++++- src/platform/apollolake/dma.c | 53 ++++++++++++++++++++++++++++++++--- src/platform/baytrail/dma.c | 41 ++++++++++++++++++++++++
src/platform/cannonlake/dma.c | 53 ++++++++++++++++++++++++++++++++--- src/platform/haswell/dma.c | 49 ++++++++++++++++++++++++++-----
- 5 files changed, 201 insertions(+), 21 deletions(-)
diff --git a/src/include/sof/dma.h b/src/include/sof/dma.h index 1de9efc..25581e6 100644 --- a/src/include/sof/dma.h +++ b/src/include/sof/dma.h @@ -48,6 +48,28 @@ enum dma_copy_dir { DMA_DIR_DEV_TO_DEV, };
+/*
- DMAC copy directions
- These are used to specify the copy direction while
requesting a DMAC
- */
+enum dmac_copy_dir {
- DMAC_DIR_READ = 0,
- DMAC_DIR_WRITE,
- DMAC_DIR_DUPLEX,
+};
On HSW and BDW, one difference between two DMA. Both DMA support Memory to memory copy, but DMA two supports memory <=> device copy. So MEM_TO_DEV, DEV_TO_MEM, HOST_TO_MEM ... should be added for this case.
Rander, there's another enum called dma_copy_dir() which defines those. Are you suggesting we qualify each DMAC with its capabilities in terms of dma_copy_dir as well?
yes, i find only dam_copy_dir is fit for capabilities. how
do you think about it?
OK, keyon has a similar suggestion and I think it makes sense. But he mentioned that for BDW, both DMAC's support all possible caps.
Could you please reply to that and correct if something is wrong? It will be useful for me when I implement. I'll verify with the HAS as well.
Hi, i just talk to keyon, no such conclusion, he just made some examples.
please do as we talked.
thank you!
+/* DMAC user types */ +enum dmac_user {
- DMAC_USER_HOST_DMA = 0,
- DMAC_USER_LINK_DMA,
- DMAC_USER_GP_LP_DMA,
- DMAC_USER_GP_HP_DMA,
+};
+/* DMAC flags */ +#define DMAC_FLAGS_SHARED 0 +#define DMAC_FLAGS_EXCLUSIVE (1 << 0)
- /* DMA IRQ types */ #define DMA_IRQ_TYPE_BLOCK (1 << 0) #define DMA_IRQ_TYPE_LLIST (1 << 1)
@@ -119,6 +141,8 @@ struct dma_ops { /* DMA platform data */ struct dma_plat_data { uint32_t id;
- enum dmac_user type;
- enum dmac_copy_dir copy_dir; uint32_t base; uint32_t channels; uint32_t irq;
@@ -139,7 +163,7 @@ struct dma_int { uint32_t irq; };
-struct dma *dma_get(int dmac_id); +struct dma *dma_get(enum dmac_user, enum dmac_copy_dir, int flags);
/* initialize all platform DMAC's */ void dmac_init(void); diff --git a/src/platform/apollolake/dma.c b/src/platform/apollolake/dma.c index 001bb67..1ae097e 100644 --- a/src/platform/apollolake/dma.c +++ b/src/platform/apollolake/dma.c @@ -112,6 +112,8 @@ static struct dma dma[] = { { /* Low Power GP DMAC 0 */ .plat_data = { .id = DMA_GP_LP_DMAC0,
.type = DMAC_USER_GP_LP_DMA,
.copy_dir = DMAC_DIR_DUPLEX, .base = LP_GP_DMA_BASE(0), .channels = 8, .irq =
IRQ_EXT_LP_GPDMA0_LVL5(0, 0), @@ -122,6 +124,8 @@ static struct dma dma[] = { { /* Low Power GP DMAC 1 */ .plat_data = { .id = DMA_GP_LP_DMAC1,
.type = DMAC_USER_GP_LP_DMA,
.copy_dir = DMAC_DIR_DUPLEX, .base = LP_GP_DMA_BASE(1), .channels = 8, .irq =
IRQ_EXT_LP_GPDMA1_LVL5(0, 0), @@ -132,6 +136,8 @@ static struct dma dma[] = { { /* Host In DMAC */ .plat_data = { .id = DMA_HOST_IN_DMAC,
.type = DMAC_USER_HOST_DMA,
.copy_dir = DMAC_DIR_WRITE, .base =
GTW_HOST_IN_STREAM_BASE(0), .channels = 7, .irq = IRQ_EXT_HOST_DMA_IN_LVL3(0, 0), @@ -142,6 +148,8 @@ static struct dma dma[] = { { /* Host out DMAC */ .plat_data = { .id = DMA_HOST_OUT_DMAC,
.type = DMAC_USER_HOST_DMA,
.copy_dir = DMAC_DIR_READ, .base =
GTW_HOST_OUT_STREAM_BASE(0), .channels = 6, .irq = IRQ_EXT_HOST_DMA_OUT_LVL3(0, 0), @@ -152,6 +160,8 @@ static struct dma dma[] = { { /* Link In DMAC */ .plat_data = { .id = DMA_LINK_IN_DMAC,
.type = DMAC_USER_LINK_DMA,
.copy_dir = DMAC_DIR_WRITE, .base =
GTW_LINK_IN_STREAM_BASE(0), .channels = 8, .irq = IRQ_EXT_LINK_DMA_IN_LVL4(0, 0), @@ -162,6 +172,8 @@ static struct dma dma[] = { { /* Link out DMAC */ .plat_data = { .id = DMA_LINK_OUT_DMAC,
.type = DMAC_USER_LINK_DMA,
.copy_dir = DMAC_DIR_READ, .base =
GTW_LINK_OUT_STREAM_BASE(0), .channels = 8, .irq = IRQ_EXT_LINK_DMA_OUT_LVL4(0, 0), @@ -170,15 +182,48 @@ static struct dma dma[] = { .ops = &hda_link_dma_ops, },};
-struct dma *dma_get(int dmac_id) +/*
- get DMAC based on user type, copy dir and flags
- "flags" is used to set the type of access requested
- (ex: shared/exclusive access)
- */
+struct dma *dma_get(enum dmac_user user, enum dmac_copy_dir dir, int flags) {
- int i;
int i, ch_count;
int dma_index = -1;
int min_ch_count = INT32_MAX;
for (i = 0; i < ARRAY_SIZE(dma); i++) {
if (dma[i].plat_data.id == dmac_id)
return &dma[i];
/* check DMAC user type */
if (dma[i].plat_data.type != user)
continue;
/* check DMAC copy dir */
if (dma[i].plat_data.copy_dir != dir)
continue;
/* if exclusive access is requested */
if (flags & DMAC_FLAGS_EXCLUSIVE) {
/* ret DMA with no channel in use */
if (!dma_channel_status(&dma[i]))
return &dma[i];
} else {
/* get number of channels in use */
ch_count =
dma_channel_status(&dma[i]);
/* Use this DMAC if its channel count
is lower */
if (ch_count < min_ch_count) {
dma_index = i;
min_ch_count = ch_count;
}
}
}
if (dma_index >= 0)
return &dma[dma_index];
return NULL; }
diff --git a/src/platform/baytrail/dma.c b/src/platform/baytrail/dma.c index 5a0b650..71ea241 100644 --- a/src/platform/baytrail/dma.c +++ b/src/platform/baytrail/dma.c @@ -175,15 +175,48 @@ static struct dma dma[] = { #endif };
-struct dma *dma_get(int dmac_id) +/*
- get DMAC based on user type, copy dir and flags
- For BYT/CHT, ignore the dmac_user and copy_dir arguments
- "flags" is used to set the type of access requested
- (ex: shared/exclusive access)
- */
+struct dma *dma_get(enum dmac_user user, enum dmac_copy_dir dir, int flags) {
- int i;
int i, ch_count;
int min_ch_count = INT32_MAX;
int dma_index = -1;
for (i = 0; i < ARRAY_SIZE(dma); i++) {
if (dma[i].plat_data.id == dmac_id)
return &dma[i];
/* if exclusive access is requested */
if (flags & DMAC_FLAGS_EXCLUSIVE) {
/* ret DMA with no channel in use */
if (!dma_channel_status(&dma[i]))
return &dma[i];
} else {
/*
* for shared access requests, return
DMAC
* with the least number of channels
in use
*/
/* get number of channels in use for
this DMAC*/
ch_count =
dma_channel_status(&dma[i]);
/* Use this DMAC if its channel count
is lower */
if (ch_count < min_ch_count) {
dma_index = i;
min_ch_count = ch_count;
}
}
}
/* return DMAC */
if (dma_index >= 0)
return &dma[dma_index];
return NULL; }
diff --git a/src/platform/cannonlake/dma.c b/src/platform/cannonlake/dma.c index 9031c17..697b9a8 100644 --- a/src/platform/cannonlake/dma.c +++ b/src/platform/cannonlake/dma.c @@ -113,6 +113,8 @@ static struct dma dma[] = { { /* Low Power GP DMAC 0 */ .plat_data = { .id = DMA_GP_LP_DMAC0,
.type = DMAC_USER_GP_LP_DMA,
.copy_dir = DMAC_DIR_DUPLEX, .base = LP_GP_DMA_BASE(0), .channels = 8, .irq = IRQ_EXT_LP_GPDMA0_LVL5(0, 0),
@@ -123,6 +125,8 @@ static struct dma dma[] = { { /* Low Power GP DMAC 1 */ .plat_data = { .id = DMA_GP_LP_DMAC1,
.type = DMAC_USER_GP_LP_DMA,
.copy_dir = DMAC_DIR_DUPLEX, .base = LP_GP_DMA_BASE(1), .channels = 8, .irq = IRQ_EXT_LP_GPDMA1_LVL5(0, 0),
@@ -133,6 +137,8 @@ static struct dma dma[] = { { /* Host In DMAC */ .plat_data = { .id = DMA_HOST_IN_DMAC,
.type = DMAC_USER_HOST_DMA,
.copy_dir = DMAC_DIR_WRITE, .base =
GTW_HOST_IN_STREAM_BASE(0), .channels = 7, .irq = IRQ_EXT_HOST_DMA_IN_LVL3(0, 0), @@ -143,6 +149,8 @@ static struct dma dma[] = { { /* Host out DMAC */ .plat_data = { .id = DMA_HOST_OUT_DMAC,
.type = DMAC_USER_HOST_DMA,
.copy_dir = DMAC_DIR_READ, .base =
GTW_HOST_OUT_STREAM_BASE(0), .channels = 9, .irq = IRQ_EXT_HOST_DMA_OUT_LVL3(0, 0), @@ -153,6 +161,8 @@ static struct dma dma[] = { { /* Link In DMAC */ .plat_data = { .id = DMA_LINK_IN_DMAC,
.type = DMAC_USER_LINK_DMA,
.copy_dir = DMAC_DIR_WRITE, .base =
GTW_LINK_IN_STREAM_BASE(0), .channels = 9, .irq = IRQ_EXT_LINK_DMA_IN_LVL4(0, 0), @@ -163,6 +173,8 @@ static struct dma dma[] = { { /* Link out DMAC */ .plat_data = { .id = DMA_LINK_OUT_DMAC,
.type = DMAC_USER_LINK_DMA,
.copy_dir = DMAC_DIR_READ, .base =
GTW_LINK_OUT_STREAM_BASE(0), .channels = 7, .irq = IRQ_EXT_LINK_DMA_OUT_LVL4(0, 0), @@ -171,15 +183,48 @@ static struct dma dma[] = { .ops = &hda_link_dma_ops, },};
-struct dma *dma_get(int dmac_id) +/*
- get DMAC based on user type, copy dir and flags
- "flags" is used to set the type of access requested
- (ex: shared/exclusive access)
- */
+struct dma *dma_get(enum dmac_user user, enum dmac_copy_dir dir, int flags) {
- int i;
int i, ch_count;
int dma_index = -1;
int min_ch_count = INT32_MAX;
for (i = 0; i < ARRAY_SIZE(dma); i++) {
if (dma[i].plat_data.id == dmac_id)
return &dma[i];
/* check DMAC user type */
if (dma[i].plat_data.type != user)
continue;
/* check DMAC copy dir */
if (dma[i].plat_data.copy_dir != dir)
continue;
/* if exclusive access is requested */
if (flags & DMAC_FLAGS_EXCLUSIVE) {
/* ret DMA with no channel in use */
if (!dma_channel_status(&dma[i]))
return &dma[i];
} else {
/* get number of channels in use */
ch_count =
dma_channel_status(&dma[i]);
/* Use this DMAC if its channel count
is lower */
if (ch_count < min_ch_count) {
dma_index = i;
min_ch_count = ch_count;
}
}
}
if (dma_index >= 0)
return &dma[dma_index];
return NULL; }
diff --git a/src/platform/haswell/dma.c b/src/platform/haswell/dma.c index 5d1e308..9138e78 100644 --- a/src/platform/haswell/dma.c +++ b/src/platform/haswell/dma.c @@ -124,16 +124,49 @@ static struct dma dma[] = { .ops = &dw_dma_ops, },};
-struct dma *dma_get(int dmac_id) +/*
- get DMAC based on user type, copy dir and flags
- For BYT/CHT, ignore the dmac_user and copy_dir arguments
- "flags" is used to set the type of access requested
- (ex: shared/exclusive access)
- */
+struct dma *dma_get(enum dmac_user user, enum dmac_copy_dir dir, int flags) {
- switch (dmac_id) {
- case DMA_ID_DMAC0:
return &dma[0];
- case DMA_ID_DMAC1:
return &dma[1];
- default:
return NULL;
- int i, ch_count;
- int min_ch_count = INT32_MAX;
- int dma_index = -1;
- for (i = 0; i < ARRAY_SIZE(dma); i++) {
/* if exclusive access is requested */
if (flags & DMAC_FLAGS_EXCLUSIVE) {
/* ret DMA with no channel in use */
if (!dma_channel_status(&dma[i]))
return &dma[i];
} else {
/*
* for shared access requests, return
DMAC
* with the least number of channels
in use
*/
/* get number of channels in use for
this DMAC*/
ch_count =
dma_channel_status(&dma[i]);
/* Use this DMAC if its channel count
is lower */
if (ch_count < min_ch_count) {
dma_index = i;
min_ch_count = ch_count;
}
}
}
/* return DMAC */
if (dma_index >= 0)
return &dma[dma_index];
return NULL; }
/* Initialize all platform DMAC's */
Sound-open-firmware mailing list Sound-open-firmware@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/sound-open-firmware