[Sound-open-firmware] [RFC PATCH 3/6] dma: introduce new API for requesting DMAC
Ranjani Sridharan
ranjani.sridharan at linux.intel.com
Tue Jun 5 06:23:17 CEST 2018
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 at 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,
+};
+
+/* 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 */
--
2.17.0
More information about the Sound-open-firmware
mailing list