From 8acabb8718239bf2aa276d551e9b91ff6d9e0a83 Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Tue, 16 Apr 2019 15:47:47 +0200 Subject: [PATCH 1/4] dw-dma: remove unused conditional code Removes unused conditional code from DW-DMA driver. Signed-off-by: Tomasz Lauda --- src/drivers/dw/dma.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/drivers/dw/dma.c b/src/drivers/dw/dma.c index 2ee595392e42..4b3933d74c70 100644 --- a/src/drivers/dw/dma.c +++ b/src/drivers/dw/dma.c @@ -1178,11 +1178,6 @@ static int dw_dma_setup(struct dma *dma) for (i = 0; i < DW_MAX_CHAN; i++) dw_read(dma, DW_DMA_CHAN_EN); -#ifdef HAVE_HDDA - /* enable HDDA before DMAC */ - shim_write(SHIM_HMDC, SHIM_HMDC_HDDA_ALLCH); -#endif - /* enable the DMA controller */ dw_write(dma, DW_DMA_CFG, 1); From c8e30e03b21bdf4ab45abc2a82c51096b1df2f3f Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Tue, 16 Apr 2019 15:53:53 +0200 Subject: [PATCH 2/4] dw-dma: set DMA suspend and drain stop from Kconfig Makes DW-DMA stop method to be configurable from Kconfig. Some of the platforms cannot stop DMA channel immediately, but first need to suspend and drain FIFO. Signed-off-by: Tomasz Lauda --- Kconfig | 13 +++++++++++ src/drivers/dw/dma.c | 51 +++++++++++--------------------------------- src/platform/Kconfig | 2 ++ 3 files changed, 28 insertions(+), 38 deletions(-) diff --git a/Kconfig b/Kconfig index ca95b65eeacf..a00c521d83bf 100644 --- a/Kconfig +++ b/Kconfig @@ -67,6 +67,19 @@ config DMA_AGGREGATED_IRQ Any platforms with DMA aggregated interrupts support should set this. +config DMA_SUSPEND_DRAIN + bool + default n + help + Some platforms cannot just simple disable DMA + channel during the transfer, because it will + hang the whole DMA controller. Instead we can + suspend the channel and drain the FIFO in order + to stop the channel as soon as possible. + + Any platforms without the ability to disable + the DMA channel right away should set this. + source "src/Kconfig" menu "Debug" diff --git a/src/drivers/dw/dma.c b/src/drivers/dw/dma.c index 4b3933d74c70..96e51d69548a 100644 --- a/src/drivers/dw/dma.c +++ b/src/drivers/dw/dma.c @@ -610,13 +610,18 @@ static int dw_dma_pause(struct dma *dma, int channel) return 0; } -#if CONFIG_BAYTRAIL || CONFIG_CHERRYTRAIL static int dw_dma_stop(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); struct dma_chan_data *chan = p->chan + channel; - int ret; uint32_t flags; +#if CONFIG_HW_LLI + int i; + struct dw_lli2 *lli; +#endif +#if CONFIG_DMA_SUSPEND_DRAIN + int ret; +#endif if (channel >= dma->plat_data.channels || channel == DMA_CHAN_INVALID) { trace_dwdma_error("dw-dma: %d invalid channel %d", @@ -624,10 +629,12 @@ static int dw_dma_stop(struct dma *dma, int channel) return -EINVAL; } - trace_dwdma("dw-dma: %d channel %d stop", dma->plat_data.id, channel); + trace_dwdma_atomic("dw-dma: %d channel %d stop", dma->plat_data.id, + channel); spin_lock_irq(&dma->lock, flags); +#if CONFIG_DMA_SUSPEND_DRAIN /* channel cannot be disabled right away, so first we need to * suspend it and drain the FIFO */ @@ -642,42 +649,13 @@ static int dw_dma_stop(struct dma *dma, int channel) if (ret < 0) trace_dwdma_error("dw-dma: %d channel %d timeout", dma->plat_data.id, channel); - - /* channel can be disabled */ - dw_write(dma, DW_DMA_CHAN_EN, CHAN_DISABLE(channel)); - - if (!chan->irq_disabled) - dw_write(dma, DW_CLEAR_BLOCK, 0x1 << channel); - - chan->status = COMP_STATE_PREPARE; - - spin_unlock_irq(&dma->lock, flags); - return ret; -} -#else -static int dw_dma_stop(struct dma *dma, int channel) -{ - struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; - uint32_t flags; -#if CONFIG_HW_LLI - int i; - struct dw_lli2 *lli; #endif - if (channel >= dma->plat_data.channels || channel == DMA_CHAN_INVALID) { - trace_dwdma_error("dw-dma: %d invalid channel %d", - dma->plat_data.id, channel); - return -EINVAL; - } - - trace_dwdma_atomic("dw-dma: %d channel %d stop", dma->plat_data.id, - channel); - - spin_lock_irq(&dma->lock, flags); - dw_write(dma, DW_DMA_CHAN_EN, CHAN_DISABLE(channel)); + /* disable interrupt */ + dw_dma_interrupt_unregister(dma, channel); + #if CONFIG_HW_LLI lli = chan->lli; for (i = 0; i < chan->desc_count; i++) { @@ -688,8 +666,6 @@ static int dw_dma_stop(struct dma *dma, int channel) dcache_writeback_region(chan->lli, sizeof(struct dw_lli2) * chan->desc_count); #endif - /* disable interrupt */ - dw_dma_interrupt_unregister(dma, channel); chan->status = COMP_STATE_PREPARE; @@ -697,7 +673,6 @@ static int dw_dma_stop(struct dma *dma, int channel) return 0; } -#endif /* fill in "status" with current DMA channel state and position */ static int dw_dma_status(struct dma *dma, int channel, diff --git a/src/platform/Kconfig b/src/platform/Kconfig index fd705ca71181..0e99dbcfb9fc 100644 --- a/src/platform/Kconfig +++ b/src/platform/Kconfig @@ -10,6 +10,7 @@ config BAYTRAIL select TASK_HAVE_PRIORITY_LOW select TASK_HAVE_PRIORITY_MEDIUM select DMA_AGGREGATED_IRQ + select DMA_SUSPEND_DRAIN help Select if your target platform is Baytrail-compatible @@ -19,6 +20,7 @@ config CHERRYTRAIL select TASK_HAVE_PRIORITY_LOW select TASK_HAVE_PRIORITY_MEDIUM select DMA_AGGREGATED_IRQ + select DMA_SUSPEND_DRAIN help Select if your target platform is Cherrytrail-compatible From 33ee23ea5c0030ca117d24a76580e768d5de807a Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Tue, 16 Apr 2019 15:59:02 +0200 Subject: [PATCH 3/4] dw-dma: make DMA FIFO partitioning configurable from Kconfig Makes DMA FIFO partitioning configurable from Kconfig. Some platforms need to set FIFO partitions before enabling DMA controller. Signed-off-by: Tomasz Lauda --- Kconfig | 10 ++++++++++ src/drivers/dw/dma.c | 4 +--- src/platform/Kconfig | 6 ++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Kconfig b/Kconfig index a00c521d83bf..929c9ac714d2 100644 --- a/Kconfig +++ b/Kconfig @@ -80,6 +80,16 @@ config DMA_SUSPEND_DRAIN Any platforms without the ability to disable the DMA channel right away should set this. +config DMA_FIFO_PARTITION + bool + default n + help + Some platforms require to manually set DMA + FIFO partitions before starting any transfer. + + Any platforms without automatic FIFO partitions + should set this. + source "src/Kconfig" menu "Debug" diff --git a/src/drivers/dw/dma.c b/src/drivers/dw/dma.c index 96e51d69548a..f1e1f342fd29 100644 --- a/src/drivers/dw/dma.c +++ b/src/drivers/dw/dma.c @@ -191,7 +191,6 @@ #define DW_CFGH_DST_PER(x) ((x) << 4) /* FIFO Partition */ -#define DW_FIFO_PARTITION #define DW_FIFO_PART0_LO 0x0400 #define DW_FIFO_PART0_HI 0x0404 #define DW_FIFO_PART1_LO 0x0408 @@ -231,7 +230,6 @@ #endif /* FIFO Partition */ -#define DW_FIFO_PARTITION #define DW_FIFO_PART0_LO 0x0400 #define DW_FIFO_PART0_HI 0x0404 #define DW_FIFO_PART1_LO 0x0408 @@ -1163,7 +1161,7 @@ static int dw_dma_setup(struct dma *dma) dw_write(dma, DW_MASK_DST_TRAN, INT_MASK_ALL); dw_write(dma, DW_MASK_ERR, INT_MASK_ALL); -#ifdef DW_FIFO_PARTITION +#if CONFIG_DMA_FIFO_PARTITION /* TODO: we cannot config DMA FIFOs if DMAC has been already */ /* allocate FIFO partitions, 128 bytes for each ch */ dw_write(dma, DW_FIFO_PART1_LO, 0x100080); diff --git a/src/platform/Kconfig b/src/platform/Kconfig index 0e99dbcfb9fc..392b00f73758 100644 --- a/src/platform/Kconfig +++ b/src/platform/Kconfig @@ -11,6 +11,7 @@ config BAYTRAIL select TASK_HAVE_PRIORITY_MEDIUM select DMA_AGGREGATED_IRQ select DMA_SUSPEND_DRAIN + select DMA_FIFO_PARTITION help Select if your target platform is Baytrail-compatible @@ -21,6 +22,7 @@ config CHERRYTRAIL select TASK_HAVE_PRIORITY_MEDIUM select DMA_AGGREGATED_IRQ select DMA_SUSPEND_DRAIN + select DMA_FIFO_PARTITION help Select if your target platform is Cherrytrail-compatible @@ -49,6 +51,7 @@ config APOLLOLAKE select TASK_HAVE_PRIORITY_LOW select TASK_HAVE_PRIORITY_MEDIUM select HW_LLI + select DMA_FIFO_PARTITION select CAVS select CAVS_VERSION_1_5 help @@ -64,6 +67,7 @@ config CANNONLAKE select TASK_HAVE_PRIORITY_MEDIUM select HW_LLI select DMA_AGGREGATED_IRQ + select DMA_FIFO_PARTITION select CAVS select CAVS_VERSION_1_8 help @@ -80,6 +84,7 @@ config SUECREEK select DW_GPIO select HW_LLI select DMA_AGGREGATED_IRQ + select DMA_FIFO_PARTITION select CAVS select CAVS_VERSION_2_0 help @@ -95,6 +100,7 @@ config ICELAKE select TASK_HAVE_PRIORITY_MEDIUM select HW_LLI select DMA_AGGREGATED_IRQ + select DMA_FIFO_PARTITION select CAVS select CAVS_VERSION_2_0 help From 9388f546e9e92e1c28dd6fa900b83db96078af65 Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Tue, 16 Apr 2019 18:31:21 +0200 Subject: [PATCH 4/4] dw-dma: cleanup the whole driver Cleanups the whole DW-DMA driver: - Move platform register defines to proper headers. - Make driver independent of platform. - Use the same accepted style of trace logs. - Other minor tweaks. Signed-off-by: Tomasz Lauda --- src/drivers/dw/dma.c | 816 +++++++----------- src/include/sof/dw-dma.h | 134 ++- .../apollolake/include/platform/dw-dma.h | 36 + .../baytrail/include/platform/dw-dma.h | 58 ++ .../cannonlake/include/platform/dw-dma.h | 36 + .../haswell/include/platform/dw-dma.h | 61 ++ .../icelake/include/platform/dw-dma.h | 36 + src/platform/intel/cavs/include/cavs/dw-dma.h | 67 ++ .../suecreek/include/platform/dw-dma.h | 36 + 9 files changed, 765 insertions(+), 515 deletions(-) create mode 100644 src/platform/apollolake/include/platform/dw-dma.h create mode 100644 src/platform/baytrail/include/platform/dw-dma.h create mode 100644 src/platform/cannonlake/include/platform/dw-dma.h create mode 100644 src/platform/haswell/include/platform/dw-dma.h create mode 100644 src/platform/icelake/include/platform/dw-dma.h create mode 100644 src/platform/intel/cavs/include/cavs/dw-dma.h create mode 100644 src/platform/suecreek/include/platform/dw-dma.h diff --git a/src/drivers/dw/dma.c b/src/drivers/dw/dma.c index f1e1f342fd29..b48a3a5e4fb1 100644 --- a/src/drivers/dw/dma.c +++ b/src/drivers/dw/dma.c @@ -43,248 +43,53 @@ * used to construct the DMA configuration for the host client 1 above. */ +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include -#include #include #include +#include #include +#include +#include +#include +#include #include #include -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include - -/* channel registers */ -#define DW_MAX_CHAN 8 -#define DW_CH_SIZE 0x58 -#define BYT_CHAN_OFFSET(chan) \ - (DW_CH_SIZE * chan) - -#define DW_SAR(chan) \ - (0x0000 + BYT_CHAN_OFFSET(chan)) -#define DW_DAR(chan) \ - (0x0008 + BYT_CHAN_OFFSET(chan)) -#define DW_LLP(chan) \ - (0x0010 + BYT_CHAN_OFFSET(chan)) -#define DW_CTRL_LOW(chan) \ - (0x0018 + BYT_CHAN_OFFSET(chan)) -#define DW_CTRL_HIGH(chan) \ - (0x001C + BYT_CHAN_OFFSET(chan)) -#define DW_CFG_LOW(chan) \ - (0x0040 + BYT_CHAN_OFFSET(chan)) -#define DW_CFG_HIGH(chan) \ - (0x0044 + BYT_CHAN_OFFSET(chan)) -#define DW_DSR(chan) \ - (0x0050 + BYT_CHAN_OFFSET(chan)) - -/* registers */ -#define DW_RAW_TFR 0x02C0 -#define DW_RAW_BLOCK 0x02C8 -#define DW_RAW_SRC_TRAN 0x02D0 -#define DW_RAW_DST_TRAN 0x02D8 -#define DW_RAW_ERR 0x02E0 -#define DW_STATUS_TFR 0x02E8 -#define DW_STATUS_BLOCK 0x02F0 -#define DW_STATUS_SRC_TRAN 0x02F8 -#define DW_STATUS_DST_TRAN 0x0300 -#define DW_STATUS_ERR 0x0308 -#define DW_MASK_TFR 0x0310 -#define DW_MASK_BLOCK 0x0318 -#define DW_MASK_SRC_TRAN 0x0320 -#define DW_MASK_DST_TRAN 0x0328 -#define DW_MASK_ERR 0x0330 -#define DW_CLEAR_TFR 0x0338 -#define DW_CLEAR_BLOCK 0x0340 -#define DW_CLEAR_SRC_TRAN 0x0348 -#define DW_CLEAR_DST_TRAN 0x0350 -#define DW_CLEAR_ERR 0x0358 -#define DW_INTR_STATUS 0x0360 -#define DW_DMA_CFG 0x0398 -#define DW_DMA_CHAN_EN 0x03A0 - -/* channel bits */ -#define INT_MASK(chan) (0x100 << chan) -#define INT_UNMASK(chan) (0x101 << chan) -#define INT_MASK_ALL 0xFF00 -#define INT_UNMASK_ALL 0xFFFF -#define CHAN_ENABLE(chan) (0x101 << chan) -#define CHAN_DISABLE(chan) (0x100 << chan) -#define CHAN_MASK(chan) (0x1 << chan) - -#define DW_CFG_CH_SUSPEND 0x100 -#define DW_CFG_CH_FIFO_EMPTY 0x200 - -/* CTL_LO */ -#define DW_CTLL_INT_EN (1 << 0) -#define DW_CTLL_DST_WIDTH(x) ((x) << 1) -#define DW_CTLL_SRC_WIDTH(x) ((x) << 4) -#define DW_CTLL_DST_INC (0 << 7) -#define DW_CTLL_DST_DEC (1 << 7) -#define DW_CTLL_DST_FIX (2 << 7) -#define DW_CTLL_SRC_INC (0 << 9) -#define DW_CTLL_SRC_DEC (1 << 9) -#define DW_CTLL_SRC_FIX (2 << 9) -#define DW_CTLL_DST_MSIZE(x) ((x) << 11) -#define DW_CTLL_SRC_MSIZE(x) ((x) << 14) -#define DW_CTLL_FC(x) ((x) << 20) -#define DW_CTLL_FC_M2M (0 << 20) -#define DW_CTLL_FC_M2P (1 << 20) -#define DW_CTLL_FC_P2M (2 << 20) -#define DW_CTLL_FC_P2P (3 << 20) -#define DW_CTLL_DMS(x) ((x) << 23) -#define DW_CTLL_SMS(x) ((x) << 25) -#define DW_CTLL_LLP_D_EN (1 << 27) -#define DW_CTLL_LLP_S_EN (1 << 28) -#define DW_CTLL_RELOAD_SRC (1 << 30) -#define DW_CTLL_RELOAD_DST (1 << 31) - -/* Haswell / Broadwell specific registers */ -#if (CONFIG_HASWELL) || (CONFIG_BROADWELL) - -/* CTL_HI */ -#define DW_CTLH_DONE(x) ((x) << 12) -#define DW_CTLH_BLOCK_TS_MASK 0x00000fff - -/* CFG_LO */ -#define DW_CFG_CLASS(x) (x << 5) - -/* CFG_HI */ -#define DW_CFGH_SRC_PER(x) (x << 7) -#define DW_CFGH_DST_PER(x) (x << 11) - -/* default initial setup register values */ -#define DW_CFG_LOW_DEF 0x0 -#define DW_CFG_HIGH_DEF 0x4 - -#elif (CONFIG_BAYTRAIL) || (CONFIG_CHERRYTRAIL) -/* baytrail specific registers */ - -/* CTL_LO */ -#define DW_CTLL_S_GATH_EN (1 << 17) -#define DW_CTLL_D_SCAT_EN (1 << 18) - -/* CTL_HI */ -#define DW_CTLH_DONE(x) ((x) << 17) -#define DW_CTLH_BLOCK_TS_MASK 0x0001ffff -#define DW_CTLH_CLASS(x) ((x) << 29) -#define DW_CTLH_WEIGHT(x) ((x) << 18) - -/* CFG_LO */ -#define DW_CFG_CH_DRAIN 0x400 - -/* CFG_HI */ -#define DW_CFGH_SRC_PER(x) ((x) << 0) -#define DW_CFGH_DST_PER(x) ((x) << 4) - -/* FIFO Partition */ -#define DW_FIFO_PART0_LO 0x0400 -#define DW_FIFO_PART0_HI 0x0404 -#define DW_FIFO_PART1_LO 0x0408 -#define DW_FIFO_PART1_HI 0x040C -#define DW_CH_SAI_ERR 0x0410 - -/* default initial setup register values */ -#define DW_CFG_LOW_DEF 0x00000003 -#define DW_CFG_HIGH_DEF 0x0 - -#elif (CONFIG_APOLLOLAKE) || (CONFIG_CANNONLAKE) || \ - (CONFIG_ICELAKE) || CONFIG_SUECREEK - -/* CTL_LO */ -#define DW_CTLL_S_GATH_EN (1 << 17) -#define DW_CTLL_D_SCAT_EN (1 << 18) - -/* CTL_HI */ -#define DW_CTLH_DONE(x) ((x) << 17) -#define DW_CTLH_BLOCK_TS_MASK 0x0001ffff -#define DW_CTLH_CLASS(x) ((x) << 29) -#define DW_CTLH_WEIGHT(x) ((x) << 18) - -/* CFG_LO */ -#define DW_CFG_CTL_HI_UPD_EN (1 << 5) -#define DW_CFG_CH_DRAIN (1 << 10) -#define DW_CFG_RELOAD_SRC (1 << 30) -#define DW_CFG_RELOAD_DST (1 << 31) - -/* CFG_HI */ -#if !(CONFIG_SUECREEK) -#define DW_CFGH_SRC_PER(x) (x << 0) -#define DW_CFGH_DST_PER(x) (x << 4) -#else -#define DW_CFGH_SRC_PER(x) ((((x) & 0xf) << 0) | (((x) & 0x30) << 24)) -#define DW_CFGH_DST_PER(x) ((((x) & 0xf) << 4) | (((x) & 0x30) << 26)) -#endif - -/* FIFO Partition */ -#define DW_FIFO_PART0_LO 0x0400 -#define DW_FIFO_PART0_HI 0x0404 -#define DW_FIFO_PART1_LO 0x0408 -#define DW_FIFO_PART1_HI 0x040C -#define DW_CH_SAI_ERR 0x0410 -#define DW_DMA_GLB_CFG 0x0418 - -/* default initial setup register values */ -#define DW_CFG_LOW_DEF 0x00000003 -#define DW_CFG_HIGH_DEF 0x0 - -#define DW_REG_MAX DW_DMA_GLB_CFG -#endif - -/* tracing */ -#define trace_dwdma(__e, ...) \ - trace_event(TRACE_CLASS_DMA, __e, ##__VA_ARGS__) -#define trace_dwdma_atomic(__e, ...) \ - trace_event_atomic(TRACE_CLASS_DMA, __e, ##__VA_ARGS__) -#define tracev_dwdma(__e, ...) \ - tracev_event(TRACE_CLASS_DMA, __e, ##__VA_ARGS__) -#define trace_dwdma_error(__e, ...) \ - trace_error(TRACE_CLASS_DMA, __e, ##__VA_ARGS__) - -/* number of tries to wait for reset */ -#define DW_DMA_CFG_TRIES 10000 - -/* min number of elems for config with irq disabled */ -#define DW_DMA_CFG_NO_IRQ_MIN_ELEMS 3 - -/* linked list item address */ -#define DW_DMA_LLI_ADDRESS(lli, dir) \ - (((dir) == DMA_DIR_MEM_TO_DEV) ? ((lli)->sar) : ((lli)->dar)) +#include -/* pointer data for dma buffer */ -struct dma_ptr_data { +/* pointer data for DW DMA buffer */ +struct dw_dma_ptr_data { uint32_t current_ptr; uint32_t start_ptr; uint32_t end_ptr; uint32_t buffer_bytes; }; -/* data for each DMA channel */ -struct dma_chan_data { +/* data for each DW DMA channel */ +struct dw_dma_chan_data { uint32_t status; uint32_t direction; - struct dw_lli2 *lli; - struct dw_lli2 *lli_current; + struct dw_lli *lli; + struct dw_lli *lli_current; uint32_t desc_count; uint32_t cfg_lo; uint32_t cfg_hi; bool irq_disabled; /* pointer data */ - struct dma_ptr_data ptr_data; + struct dw_dma_ptr_data ptr_data; /* client callback function */ void (*cb)(void *data, uint32_t type, struct dma_sg_elem *next); @@ -296,14 +101,21 @@ struct dma_chan_data { /* private data for DW DMA engine */ struct dma_pdata { - struct dma_chan_data chan[DW_MAX_CHAN]; - uint32_t class; /* channel class - set for controller atm */ + struct dw_dma_chan_data chan[DW_MAX_CHAN]; }; +/* use array to get burst_elems for specific slot number setting. + * the relation between msize and burst_elems should be + * 2 ^ msize = burst_elems + */ +static const uint32_t burst_elems[] = {1, 2, 4, 8}; + +#if !CONFIG_HW_LLI static inline void dw_dma_chan_reload_lli(struct dma *dma, int channel); static inline void dw_dma_chan_reload_next(struct dma *dma, int channel, struct dma_sg_elem *next, int direction); +#endif static inline int dw_dma_interrupt_register(struct dma *dma, int channel); static inline void dw_dma_interrupt_unregister(struct dma *dma, int channel); static int dw_dma_copy(struct dma *dma, int channel, int bytes, uint32_t flags); @@ -318,27 +130,21 @@ static inline uint32_t dw_read(struct dma *dma, uint32_t reg) return io_reg_read(dma_base(dma) + reg); } -static inline void dw_update_bits(struct dma *dma, uint32_t reg, uint32_t mask, - uint32_t value) -{ - io_reg_update_bits(dma_base(dma) + reg, mask, value); -} - static void dw_dma_interrupt_mask(struct dma *dma, int channel) { const struct dma_pdata *p = dma_get_drvdata(dma); if (p->chan[channel].irq_disabled) { - tracev_event(TRACE_CLASS_DMA, "dw_dma_interrupt_mask(): " - "dma %d channel %d not working in irq mode", - dma->plat_data.id, channel); + tracev_dwdma("dw_dma_interrupt_mask(): dma %d channel %d " + "not working in irq mode", dma->plat_data.id, + channel); return; } /* mask block, transfer and error interrupts for channel */ - dw_write(dma, DW_MASK_TFR, INT_MASK(channel)); - dw_write(dma, DW_MASK_BLOCK, INT_MASK(channel)); - dw_write(dma, DW_MASK_ERR, INT_MASK(channel)); + dw_write(dma, DW_MASK_TFR, DW_CHAN_MASK(channel)); + dw_write(dma, DW_MASK_BLOCK, DW_CHAN_MASK(channel)); + dw_write(dma, DW_MASK_ERR, DW_CHAN_MASK(channel)); } static void dw_dma_interrupt_unmask(struct dma *dma, int channel) @@ -346,19 +152,19 @@ static void dw_dma_interrupt_unmask(struct dma *dma, int channel) const struct dma_pdata *p = dma_get_drvdata(dma); if (p->chan[channel].irq_disabled) { - tracev_event(TRACE_CLASS_DMA, "dw_dma_interrupt_mask(): " - "dma %d channel %d not working in irq mode", - dma->plat_data.id, channel); + tracev_dwdma("dw_dma_interrupt_mask(): dma %d channel %d " + "not working in irq mode", dma->plat_data.id, + channel); return; } /* unmask block, transfer and error interrupts for channel */ #if CONFIG_HW_LLI - dw_write(dma, DW_MASK_BLOCK, INT_UNMASK(channel)); + dw_write(dma, DW_MASK_BLOCK, DW_CHAN_UNMASK(channel)); #else - dw_write(dma, DW_MASK_TFR, INT_UNMASK(channel)); + dw_write(dma, DW_MASK_TFR, DW_CHAN_UNMASK(channel)); #endif - dw_write(dma, DW_MASK_ERR, INT_UNMASK(channel)); + dw_write(dma, DW_MASK_ERR, DW_CHAN_UNMASK(channel)); } static void dw_dma_interrupt_clear(struct dma *dma, int channel) @@ -366,23 +172,22 @@ static void dw_dma_interrupt_clear(struct dma *dma, int channel) const struct dma_pdata *p = dma_get_drvdata(dma); if (p->chan[channel].irq_disabled) { - tracev_event(TRACE_CLASS_DMA, "dw_dma_interrupt_mask(): " - "dma %d channel %d not working in irq mode", - dma->plat_data.id, channel); + tracev_dwdma("dw_dma_interrupt_mask(): dma %d channel %d " + "not working in irq mode", dma->plat_data.id, + channel); return; } - /* write interrupt clear registers for the channel: - * ClearTfr, ClearBlock, ClearSrcTran, ClearDstTran, ClearErr - */ - dw_write(dma, DW_CLEAR_TFR, 0x1 << channel); - dw_write(dma, DW_CLEAR_BLOCK, 0x1 << channel); - dw_write(dma, DW_CLEAR_SRC_TRAN, 0x1 << channel); - dw_write(dma, DW_CLEAR_DST_TRAN, 0x1 << channel); - dw_write(dma, DW_CLEAR_ERR, 0x1 << channel); + /* clear transfer, block, src, dst and error interrupts for channel */ + dw_write(dma, DW_CLEAR_TFR, DW_CHAN(channel)); + dw_write(dma, DW_CLEAR_BLOCK, DW_CHAN(channel)); + dw_write(dma, DW_CLEAR_SRC_TRAN, DW_CHAN(channel)); + dw_write(dma, DW_CLEAR_DST_TRAN, DW_CHAN(channel)); + dw_write(dma, DW_CLEAR_ERR, DW_CHAN(channel)); /* clear platform interrupt */ - platform_interrupt_clear(dma_irq(dma, cpu_get_id()), 1 << channel); + platform_interrupt_clear(dma_irq(dma, cpu_get_id()), + DW_CHAN(channel)); } /* allocate next free DMA channel */ @@ -392,7 +197,8 @@ static int dw_dma_channel_get(struct dma *dma, int req_chan) uint32_t flags; int i; - trace_dwdma("dw-dma %d request channel", dma->plat_data.id); + trace_dwdma("dw_dma_channel_get(): dma %d request channel %d", + dma->plat_data.id, req_chan); spin_lock_irq(&dma->lock, flags); @@ -412,9 +218,11 @@ static int dw_dma_channel_get(struct dma *dma, int req_chan) return i; } - /* DMAC has no free channels */ + /* DMA controller has no free channels */ spin_unlock_irq(&dma->lock, flags); - trace_dwdma_error("dw-dma %d no channel is free", dma->plat_data.id); + trace_dwdma_error("dw_dma_channel_get() error: dma %d " + "no free channels", dma->plat_data.id); + return -ENODEV; } @@ -422,10 +230,12 @@ static int dw_dma_channel_get(struct dma *dma, int req_chan) static void dw_dma_channel_put_unlocked(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; + struct dw_dma_chan_data *chan = p->chan + channel; - if (channel >= dma->plat_data.channels) { - trace_dwdma_error("dw-dma: %d invalid channel %d", + if (channel >= dma->plat_data.channels || + channel == DMA_CHAN_INVALID) { + trace_dwdma_error("dw_dma_channel_put_unlocked() error: " + "dma %d invalid channel %d", dma->plat_data.id, channel); return; } @@ -454,7 +264,8 @@ static void dw_dma_channel_put(struct dma *dma, int channel) { uint32_t flags; - trace_dwdma("dw-dma: %d channel %d put", dma->plat_data.id, channel); + trace_dwdma("dw_dma_channel_put(): dma %d channel %d put", + dma->plat_data.id, channel); spin_lock_irq(&dma->lock, flags); dw_dma_channel_put_unlocked(dma, channel); @@ -464,107 +275,115 @@ static void dw_dma_channel_put(struct dma *dma, int channel) static int dw_dma_start(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; - struct dw_lli2 *lli = chan->lli_current; + struct dw_dma_chan_data *chan = p->chan + channel; + struct dw_lli *lli = chan->lli_current; uint32_t flags; int ret = 0; +#if CONFIG_HW_LLI + uint32_t words_per_tfr = 0; +#endif - if (channel >= dma->plat_data.channels) { - trace_dwdma_error("dw-dma: %d invalid channel %d", - dma->plat_data.id, channel); + if (channel >= dma->plat_data.channels || + channel == DMA_CHAN_INVALID) { + trace_dwdma_error("dw_dma_start() error: dma %d invalid " + "channel %d", dma->plat_data.id, channel); return -EINVAL; } - tracev_dwdma("dw-dma: %d channel %d start", dma->plat_data.id, channel); + tracev_dwdma("dw_dma_start(): dma %d channel %d start", + dma->plat_data.id, channel); spin_lock_irq(&dma->lock, flags); - /* is channel idle, disabled and ready ? */ + /* check if channel idle, disabled and ready */ if (chan->status != COMP_STATE_PREPARE || - (dw_read(dma, DW_DMA_CHAN_EN) & (0x1 << channel))) { - ret = -EBUSY; - trace_dwdma_error("dw-dma: %d channel %d not ready", - dma->plat_data.id, channel); - trace_dwdma_error(" ena 0x%x cfglow 0x%x status 0x%x", + (dw_read(dma, DW_DMA_CHAN_EN) & DW_CHAN(channel))) { + trace_dwdma_error("dw_dma_start() error: dma %d channel %d " + "not ready ena 0x%x status 0x%x", + dma->plat_data.id, channel, dw_read(dma, DW_DMA_CHAN_EN), - dw_read(dma, DW_CFG_LOW(channel)), chan->status); + ret = -EBUSY; goto out; } - /* valid stream ? */ - if (chan->lli == NULL) { + /* is valid stream */ + if (!chan->lli) { + trace_dwdma_error("dw_dma_start() error: dma %d channel %d " + "invalid stream", dma->plat_data.id, + channel); ret = -EINVAL; - trace_dwdma_error("dw-dma: %d channel %d invalid stream", - dma->plat_data.id, channel); goto out; } dw_dma_interrupt_clear(dma, channel); #if CONFIG_HW_LLI - /* TODO: Revisit: are we using LLP mode or single transfer ? */ /* LLP mode - write LLP pointer unless in scatter mode */ dw_write(dma, DW_LLP(channel), lli->ctrl_lo & (DW_CTLL_LLP_D_EN | DW_CTLL_LLP_S_EN) ? (uint32_t)lli : 0); #endif - /* channel needs started from scratch, so write SARn, DARn */ + /* channel needs to start from scratch, so write SAR and DAR */ dw_write(dma, DW_SAR(channel), lli->sar); dw_write(dma, DW_DAR(channel), lli->dar); - /* program CTLn */ + /* program CTL_LO and CTL_HI */ dw_write(dma, DW_CTRL_LOW(channel), lli->ctrl_lo); dw_write(dma, DW_CTRL_HIGH(channel), lli->ctrl_hi); - /* write channel config */ + /* program CFG_LO and CFG_HI */ dw_write(dma, DW_CFG_LOW(channel), chan->cfg_lo); dw_write(dma, DW_CFG_HIGH(channel), chan->cfg_hi); #if CONFIG_HW_LLI if (lli->ctrl_lo & DW_CTLL_D_SCAT_EN) { - unsigned int words_per_tfr = (lli->ctrl_hi & 0x1ffff) >> - (lli->ctrl_lo >> 1 & 0x7); - dw_write(dma, DW_DSR(channel), - words_per_tfr | words_per_tfr << 20); + words_per_tfr = (lli->ctrl_hi & DW_CTLH_BLOCK_TS_MASK) >> + ((lli->ctrl_lo & DW_CTLL_DST_WIDTH_MASK) >> + DW_CTLL_DST_WIDTH_SHIFT); + dw_write(dma, DW_DSR(channel), DW_DSR_DSC(words_per_tfr) | + DW_DSR_DSI(words_per_tfr)); } #endif + /* enable interrupt only for the first start */ if (chan->status == COMP_STATE_PREPARE) - /* enable interrupt only for the first start */ ret = dw_dma_interrupt_register(dma, channel); - if (ret == 0) { + if (!ret) { /* enable the channel */ chan->status = COMP_STATE_ACTIVE; - dw_write(dma, DW_DMA_CHAN_EN, CHAN_ENABLE(channel)); + dw_write(dma, DW_DMA_CHAN_EN, DW_CHAN_UNMASK(channel)); } out: spin_unlock_irq(&dma->lock, flags); + return ret; } static int dw_dma_release(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; + struct dw_dma_chan_data *chan = p->chan + channel; uint32_t next_ptr; uint32_t bytes_left; uint32_t flags; - if (channel >= dma->plat_data.channels) { - trace_dwdma_error("dw-dma: %d invalid channel %d", - dma->plat_data.id, channel); + if (channel >= dma->plat_data.channels || + channel == DMA_CHAN_INVALID) { + trace_dwdma_error("dw_dma_release() error: dma %d invalid " + "channel %d", dma->plat_data.id, channel); return -EINVAL; } - trace_dwdma("dw-dma: %d channel %d release", dma->plat_data.id, channel); + trace_dwdma("dw_dma_release(): dma %d channel %d release", + dma->plat_data.id, channel); spin_lock_irq(&dma->lock, flags); /* get next lli for proper release */ - chan->lli_current = (struct dw_lli2 *)chan->lli_current->llp; + chan->lli_current = (struct dw_lli *)chan->lli_current->llp; /* copy leftover data between current and last lli */ next_ptr = DW_DMA_LLI_ADDRESS(chan->lli_current, chan->direction); @@ -579,56 +398,62 @@ static int dw_dma_release(struct dma *dma, int channel) dw_dma_copy(dma, channel, bytes_left, 0); spin_unlock_irq(&dma->lock, flags); + return 0; } static int dw_dma_pause(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); + struct dw_dma_chan_data *chan = p->chan + channel; uint32_t flags; - if (channel >= dma->plat_data.channels) { - trace_dwdma_error("dw-dma: %d invalid channel %d", - dma->plat_data.id, channel); + if (channel >= dma->plat_data.channels || + channel == DMA_CHAN_INVALID) { + trace_dwdma_error("dw_dma_pause() error: dma %d invalid " + "channel %d", dma->plat_data.id, channel); return -EINVAL; } - trace_dwdma("dw-dma: %d channel %d pause", dma->plat_data.id, channel); + trace_dwdma("dw_dma_pause(): dma %d channel %d pause", + dma->plat_data.id, channel); spin_lock_irq(&dma->lock, flags); - if (p->chan[channel].status != COMP_STATE_ACTIVE) + if (chan->status != COMP_STATE_ACTIVE) goto out; /* pause the channel */ - p->chan[channel].status = COMP_STATE_PAUSED; + chan->status = COMP_STATE_PAUSED; out: spin_unlock_irq(&dma->lock, flags); + return 0; } static int dw_dma_stop(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; + struct dw_dma_chan_data *chan = p->chan + channel; uint32_t flags; #if CONFIG_HW_LLI + struct dw_lli *lli = chan->lli; int i; - struct dw_lli2 *lli; #endif #if CONFIG_DMA_SUSPEND_DRAIN int ret; #endif - if (channel >= dma->plat_data.channels || channel == DMA_CHAN_INVALID) { - trace_dwdma_error("dw-dma: %d invalid channel %d", - dma->plat_data.id, channel); + if (channel >= dma->plat_data.channels || + channel == DMA_CHAN_INVALID) { + trace_dwdma_error("dw_dma_stop() error: dma %d invalid " + "channel %d", dma->plat_data.id, channel); return -EINVAL; } - trace_dwdma_atomic("dw-dma: %d channel %d stop", dma->plat_data.id, - channel); + trace_dwdma("dw_dma_stop(): dma %d channel %d stop", + dma->plat_data.id, channel); spin_lock_irq(&dma->lock, flags); @@ -636,33 +461,32 @@ static int dw_dma_stop(struct dma *dma, int channel) /* channel cannot be disabled right away, so first we need to * suspend it and drain the FIFO */ - dw_write(dma, DW_CFG_LOW(channel), chan->cfg_lo | DW_CFG_CH_SUSPEND | - DW_CFG_CH_DRAIN); + dw_write(dma, DW_CFG_LOW(channel), chan->cfg_lo | DW_CFGL_SUSPEND | + DW_CFGL_DRAIN); /* now we wait for FIFO to be empty */ ret = poll_for_register_delay(dma_base(dma) + DW_CFG_LOW(channel), - DW_CFG_CH_FIFO_EMPTY, - DW_CFG_CH_FIFO_EMPTY, + DW_CFGL_FIFO_EMPTY, + DW_CFGL_FIFO_EMPTY, PLATFORM_DMA_TIMEOUT); if (ret < 0) - trace_dwdma_error("dw-dma: %d channel %d timeout", - dma->plat_data.id, channel); + trace_dwdma_error("dw_dma_stop() error: dma %d channel %d " + "timeout", dma->plat_data.id, channel); #endif - dw_write(dma, DW_DMA_CHAN_EN, CHAN_DISABLE(channel)); + dw_write(dma, DW_DMA_CHAN_EN, DW_CHAN_MASK(channel)); /* disable interrupt */ dw_dma_interrupt_unregister(dma, channel); #if CONFIG_HW_LLI - lli = chan->lli; for (i = 0; i < chan->desc_count; i++) { lli->ctrl_hi &= ~DW_CTLH_DONE(1); lli++; } dcache_writeback_region(chan->lli, - sizeof(struct dw_lli2) * chan->desc_count); + sizeof(struct dw_lli) * chan->desc_count); #endif chan->status = COMP_STATE_PREPARE; @@ -678,14 +502,16 @@ static int dw_dma_status(struct dma *dma, int channel, uint8_t direction) { struct dma_pdata *p = dma_get_drvdata(dma); + struct dw_dma_chan_data *chan = p->chan + channel; - if (channel >= dma->plat_data.channels) { - trace_dwdma_error("dw-dma: %d invalid channel %d", - dma->plat_data.id, channel); + if (channel >= dma->plat_data.channels || + channel == DMA_CHAN_INVALID) { + trace_dwdma_error("dw_dma_status() error: dma %d invalid " + "channel %d", dma->plat_data.id, channel); return -EINVAL; } - status->state = p->chan[channel].status; + status->state = chan->status; status->r_pos = dw_read(dma, DW_SAR(channel)); status->w_pos = dw_read(dma, DW_DAR(channel)); status->timestamp = timer_get_system(platform_timer); @@ -697,10 +523,8 @@ static int dw_dma_status(struct dma *dma, int channel, * It is requested by BYT, HSW, BDW. For other * platforms, the mask is zero. */ -static void dw_dma_mask_address(struct dma_sg_elem *sg_elem, - uint32_t *sar, - uint32_t *dar, - uint32_t direction) +static void dw_dma_mask_address(struct dma_sg_elem *sg_elem, uint32_t *sar, + uint32_t *dar, uint32_t direction) { *sar = sg_elem->src; *dar = sg_elem->dest; @@ -723,38 +547,37 @@ static void dw_dma_mask_address(struct dma_sg_elem *sg_elem, } } -/* - * use array to get burst_elems for specific slot number setting. - * the relation between msize and burst_elems should be - * 2 ^ msize = burst_elems - */ -static const uint32_t burst_elems[] = {1, 2, 4, 8}; - /* set the DMA channel configuration, source/target address, buffer sizes */ static int dw_dma_set_config(struct dma *dma, int channel, struct dma_sg_config *config) { + struct dw_drv_plat_data *dp = dma->plat_data.drv_plat_data; struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; + struct dw_dma_chan_data *chan = p->chan + channel; struct dma_sg_elem *sg_elem; - struct dw_lli2 *lli_desc; - struct dw_lli2 *lli_desc_head; - struct dw_lli2 *lli_desc_tail; - uint32_t flags; + struct dw_lli *lli_desc; + struct dw_lli *lli_desc_head; + struct dw_lli *lli_desc_tail; + uint16_t chan_class; uint32_t msize = 3;/* default msize */ - int i, ret = 0; + uint32_t flags; + int ret = 0; + int i; - if (channel >= dma->plat_data.channels) { - trace_dwdma_error("dw-dma: %d invalid channel %d", - dma->plat_data.id, channel); + if (channel >= dma->plat_data.channels || + channel == DMA_CHAN_INVALID) { + trace_dwdma_error("dw_dma_set_config() error: dma %d invalid " + "channel %d", dma->plat_data.id, channel); return -EINVAL; } - tracev_dwdma("dw-dma: %d channel %d config", dma->plat_data.id, - channel); + tracev_dwdma("dw_dma_set_config(): dma %d channel %d config", + dma->plat_data.id, channel); spin_lock_irq(&dma->lock, flags); + chan_class = dp->chan[channel].class; + /* default channel config */ chan->direction = config->direction; chan->irq_disabled = config->irq_disabled; @@ -762,17 +585,18 @@ static int dw_dma_set_config(struct dma *dma, int channel, chan->cfg_hi = DW_CFG_HIGH_DEF; if (!config->elem_array.count) { - trace_dwdma_error("dw-dma: %d channel %d no elems", - dma->plat_data.id, channel); + trace_dwdma_error("dw_dma_set_config() error: dma %d " + "channel %d no elems", dma->plat_data.id, + channel); ret = -EINVAL; goto out; } if (config->irq_disabled && config->elem_array.count < DW_DMA_CFG_NO_IRQ_MIN_ELEMS) { - trace_dwdma_error("dw-dma: %d channel %d not enough elems " - "for config with irq disabled", - dma->plat_data.id, channel, + trace_dwdma_error("dw_dma_set_config() error: dma %d channel " + "%d not enough elems for config with irq " + "disabled %d", dma->plat_data.id, channel, config->elem_array.count); ret = -EINVAL; goto out; @@ -786,12 +610,13 @@ static int dw_dma_set_config(struct dma *dma, int channel, /* allocate descriptors for channel */ if (chan->lli) rfree(chan->lli); - chan->lli = rzalloc(RZONE_SYS_RUNTIME, - SOF_MEM_CAPS_RAM | SOF_MEM_CAPS_DMA, - sizeof(struct dw_lli2) * - chan->desc_count); - if (chan->lli == NULL) { - trace_dwdma_error("dw-dma: %d channel %d LLI alloc failed", + + chan->lli = rzalloc(RZONE_SYS_RUNTIME, SOF_MEM_CAPS_RAM | + SOF_MEM_CAPS_DMA, sizeof(struct dw_lli) * + chan->desc_count); + if (!chan->lli) { + trace_dwdma_error("dw_dma_set_config() error: dma %d " + "channel %d lli alloc failed", dma->plat_data.id, channel); ret = -ENOMEM; goto out; @@ -799,14 +624,13 @@ static int dw_dma_set_config(struct dma *dma, int channel, } /* initialise descriptors */ - bzero(chan->lli, sizeof(struct dw_lli2) * chan->desc_count); + bzero(chan->lli, sizeof(struct dw_lli) * chan->desc_count); lli_desc = chan->lli; lli_desc_head = chan->lli; lli_desc_tail = chan->lli + chan->desc_count - 1; /* configure msize if burst_elems is set */ if (config->burst_elems) { - /* burst_elems set, configure msize */ for (i = 0; i < ARRAY_SIZE(burst_elems); i++) { if (burst_elems[i] == config->burst_elems) { msize = i; @@ -819,12 +643,11 @@ static int dw_dma_set_config(struct dma *dma, int channel, chan->ptr_data.buffer_bytes = 0; - /* fill in lli for the elem in the list */ + /* fill in lli for the elems in the list */ for (i = 0; i < config->elem_array.count; i++) { - sg_elem = config->elem_array.elems + i; - /* write CTL_LOn for each lli */ + /* write CTL_LO for each lli */ switch (config->src_width) { case 2: /* non peripheral copies are optimal using words */ @@ -846,7 +669,8 @@ static int dw_dma_set_config(struct dma *dma, int channel, lli_desc->ctrl_lo |= DW_CTLL_SRC_WIDTH(2); break; default: - trace_dwdma_error("dw-dma: %d channel %d invalid src width %d", + trace_dwdma_error("dw_dma_set_config() error: dma %d " + "channel %d invalid src width %d", dma->plat_data.id, channel, config->src_width); ret = -EINVAL; @@ -874,7 +698,8 @@ static int dw_dma_set_config(struct dma *dma, int channel, lli_desc->ctrl_lo |= DW_CTLL_DST_WIDTH(2); break; default: - trace_dwdma_error("dw-dma: %d channel %d invalid dest width %d", + trace_dwdma_error("dw_dma_set_config() error: dma %d " + "channel %d invalid dest width %d", dma->plat_data.id, channel, config->dest_width); ret = -EINVAL; @@ -885,8 +710,8 @@ static int dw_dma_set_config(struct dma *dma, int channel, DW_CTLL_DST_MSIZE(msize) | DW_CTLL_INT_EN; /* enable interrupt */ - /* config the SINC and DINC field of CTL_LOn, - * SRC/DST_PER filed of CFGn + /* config the SINC and DINC fields of CTL_LO, + * SRC/DST_PER fields of CFG_HI */ switch (config->direction) { case DMA_DIR_LMEM_TO_HMEM: @@ -920,7 +745,7 @@ static int dw_dma_set_config(struct dma *dma, int channel, lli_desc->ctrl_lo |= DW_CTLL_LLP_S_EN; chan->cfg_lo |= DW_CFG_RELOAD_DST; #endif - chan->cfg_hi |= DW_CFGH_DST_PER(config->dest_dev); + chan->cfg_hi |= DW_CFGH_DST(config->dest_dev); break; case DMA_DIR_DEV_TO_MEM: lli_desc->ctrl_lo |= DW_CTLL_FC_P2M | DW_CTLL_SRC_FIX | @@ -929,14 +754,13 @@ static int dw_dma_set_config(struct dma *dma, int channel, if (!config->scatter) lli_desc->ctrl_lo |= DW_CTLL_LLP_D_EN; else - /* - * Use contiguous auto-reload. Line 3 in + /* Use contiguous auto-reload. Line 3 in * table 3-3 */ lli_desc->ctrl_lo |= DW_CTLL_D_SCAT_EN; chan->cfg_lo |= DW_CFG_RELOAD_SRC; #endif - chan->cfg_hi |= DW_CFGH_SRC_PER(config->src_dev); + chan->cfg_hi |= DW_CFGH_SRC(config->src_dev); break; case DMA_DIR_DEV_TO_DEV: lli_desc->ctrl_lo |= DW_CTLL_FC_P2P | DW_CTLL_SRC_FIX | @@ -945,11 +769,12 @@ static int dw_dma_set_config(struct dma *dma, int channel, lli_desc->ctrl_lo |= DW_CTLL_LLP_S_EN | DW_CTLL_LLP_D_EN; #endif - chan->cfg_hi |= DW_CFGH_SRC_PER(config->src_dev) | - DW_CFGH_DST_PER(config->dest_dev); + chan->cfg_hi |= DW_CFGH_SRC(config->src_dev) | + DW_CFGH_DST(config->dest_dev); break; default: - trace_dwdma_error("dw-dma: %d channel %d invalid direction %d", + trace_dwdma_error("dw_dma_set_config() error: dma %d " + "channel %d invalid direction %d", dma->plat_data.id, channel, config->direction); ret = -EINVAL; @@ -960,25 +785,20 @@ static int dw_dma_set_config(struct dma *dma, int channel, config->direction); if (sg_elem->size > DW_CTLH_BLOCK_TS_MASK) { - trace_dwdma_error("dw-dma: %d channel %d block size too big %d", + trace_dwdma_error("dw_dma_set_config() error: dma %d " + "channel %d block size too big %d", dma->plat_data.id, channel, sg_elem->size); ret = -EINVAL; goto out; } + /* set channel class */ + platform_dw_dma_set_class(chan, lli_desc, chan_class); + /* set transfer size of element */ -#if CONFIG_BAYTRAIL || CONFIG_CHERRYTRAIL || \ - CONFIG_APOLLOLAKE || CONFIG_CANNONLAKE || \ - CONFIG_ICELAKE || CONFIG_SUECREEK - lli_desc->ctrl_hi = DW_CTLH_CLASS(p->class) | - (sg_elem->size & DW_CTLH_BLOCK_TS_MASK); -#elif CONFIG_BROADWELL || CONFIG_HASWELL - /* for bdw, the unit is transaction--TR_WIDTH. */ - lli_desc->ctrl_hi = (sg_elem->size / - (1 << (lli_desc->ctrl_lo >> 4 & 0x7))) - & DW_CTLH_BLOCK_TS_MASK; -#endif + platform_dw_dma_set_transfer_size(chan, lli_desc, + sg_elem->size); chan->ptr_data.buffer_bytes += sg_elem->size; @@ -993,11 +813,11 @@ static int dw_dma_set_config(struct dma *dma, int channel, chan->cfg_lo |= DW_CFG_CTL_HI_UPD_EN; #endif - /* end of list or cyclic buffer ? */ + /* end of list or cyclic buffer */ if (config->cyclic) { lli_desc_tail->llp = (uint32_t)lli_desc_head; } else { - lli_desc_tail->llp = 0x0; + lli_desc_tail->llp = 0; #if CONFIG_HW_LLI lli_desc_tail->ctrl_lo &= ~(DW_CTLL_LLP_S_EN | DW_CTLL_LLP_D_EN); @@ -1006,7 +826,7 @@ static int dw_dma_set_config(struct dma *dma, int channel, /* write back descriptors so DMA engine can read them directly */ dcache_writeback_region(chan->lli, - sizeof(struct dw_lli2) * chan->desc_count); + sizeof(struct dw_lli) * chan->desc_count); chan->status = COMP_STATE_PREPARE; chan->lli_current = chan->lli; @@ -1020,16 +840,17 @@ static int dw_dma_set_config(struct dma *dma, int channel, out: spin_unlock_irq(&dma->lock, flags); + return ret; } -/* restore DMA conext after leaving D3 */ +/* restore DMA context after leaving D3 */ static int dw_dma_pm_context_restore(struct dma *dma) { return 0; } -/* store DMA conext after leaving D3 */ +/* store DMA context before leaving D0 */ static int dw_dma_pm_context_store(struct dma *dma) { /* disable the DMA controller */ @@ -1039,11 +860,12 @@ static int dw_dma_pm_context_store(struct dma *dma) } static int dw_dma_set_cb(struct dma *dma, int channel, int type, - void (*cb)(void *data, uint32_t type, struct dma_sg_elem *next), - void *data) + void (*cb)(void *data, uint32_t type, + struct dma_sg_elem *next), + void *data) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; + struct dw_dma_chan_data *chan = p->chan + channel; uint32_t flags; spin_lock_irq(&dma->lock, flags); @@ -1055,37 +877,38 @@ static int dw_dma_set_cb(struct dma *dma, int channel, int type, return 0; } +#if !CONFIG_HW_LLI /* reload using LLI data */ static inline void dw_dma_chan_reload_lli(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; - struct dw_lli2 *lli = chan->lli_current; + struct dw_dma_chan_data *chan = p->chan + channel; + struct dw_lli *lli = chan->lli_current; /* only need to reload if this is a block transfer */ - if (!lli || lli->llp == 0) { + if (!lli || !lli->llp) { chan->status = COMP_STATE_PREPARE; return; } /* get current and next block pointers */ - lli = (struct dw_lli2 *)lli->llp; + lli = (struct dw_lli *)lli->llp; chan->lli_current = lli; - /* channel needs started from scratch, so write SARn, DARn */ + /* channel needs to start from scratch, so write SAR and DAR */ dw_write(dma, DW_SAR(channel), lli->sar); dw_write(dma, DW_DAR(channel), lli->dar); - /* program CTLn */ + /* program CTL_LO and CTL_HI */ dw_write(dma, DW_CTRL_LOW(channel), lli->ctrl_lo); dw_write(dma, DW_CTRL_HIGH(channel), lli->ctrl_hi); - /* program CFGn */ + /* program CFG_LO and CFG_HI */ dw_write(dma, DW_CFG_LOW(channel), chan->cfg_lo); dw_write(dma, DW_CFG_HIGH(channel), chan->cfg_hi); /* enable the channel */ - dw_write(dma, DW_DMA_CHAN_EN, CHAN_ENABLE(channel)); + dw_write(dma, DW_DMA_CHAN_EN, DW_CHAN_UNMASK(channel)); } /* reload using callback data */ @@ -1093,118 +916,57 @@ static inline void dw_dma_chan_reload_next(struct dma *dma, int channel, struct dma_sg_elem *next, int direction) { + struct dw_drv_plat_data *dp = dma->plat_data.drv_plat_data; + uint16_t class = dp->chan[channel].class; struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; - struct dw_lli2 *lli = chan->lli_current; - uint32_t sar, dar; + struct dw_dma_chan_data *chan = p->chan + channel; + struct dw_lli *lli = chan->lli_current; + uint32_t sar; + uint32_t dar; dw_dma_mask_address(next, &sar, &dar, direction); - /* channel needs started from scratch, so write SARn, DARn */ + /* channel needs to start from scratch, so write SAR and DAR */ dw_write(dma, DW_SAR(channel), sar); dw_write(dma, DW_DAR(channel), dar); + /* set channel class */ + platform_dw_dma_set_class(chan, lli, class); + /* set transfer size of element */ -#if CONFIG_BAYTRAIL || CONFIG_CHERRYTRAIL \ - || CONFIG_APOLLOLAKE || CONFIG_CANNONLAKE \ - || CONFIG_ICELAKE || CONFIG_SUECREEK - lli->ctrl_hi = DW_CTLH_CLASS(p->class) | - (next->size & DW_CTLH_BLOCK_TS_MASK); -#elif CONFIG_BROADWELL || CONFIG_HASWELL - /* for the unit is transaction--TR_WIDTH. */ - lli->ctrl_hi = (next->size / (1 << (lli->ctrl_lo >> 4 & 0x7))) - & DW_CTLH_BLOCK_TS_MASK; -#endif + platform_dw_dma_set_transfer_size(chan, lli, next->size); - /* program CTLn */ + /* program CTL_LO and CTL_HI */ dw_write(dma, DW_CTRL_LOW(channel), lli->ctrl_lo); dw_write(dma, DW_CTRL_HIGH(channel), lli->ctrl_hi); - /* program CFGn */ + /* program CFG_LO and CFG_HI */ dw_write(dma, DW_CFG_LOW(channel), chan->cfg_lo); dw_write(dma, DW_CFG_HIGH(channel), chan->cfg_hi); /* enable the channel */ - dw_write(dma, DW_DMA_CHAN_EN, CHAN_ENABLE(channel)); + dw_write(dma, DW_DMA_CHAN_EN, DW_CHAN_UNMASK(channel)); } - -static int dw_dma_setup(struct dma *dma) -{ - struct dw_drv_plat_data *dp = dma->plat_data.drv_plat_data; - int i; - - /* we cannot config DMAC if DMAC has been already enabled by host */ - if (dw_read(dma, DW_DMA_CFG) != 0) - dw_write(dma, DW_DMA_CFG, 0x0); - - /* now check that it's 0 */ - for (i = DW_DMA_CFG_TRIES; i > 0; i--) - if (dw_read(dma, DW_DMA_CFG) == 0) - break; - - if (!i) { - trace_dwdma_error("dw-dma: dmac %d setup failed", - dma->plat_data.id); - return -EIO; - } - - for (i = 0; i < DW_MAX_CHAN; i++) - dw_read(dma, DW_DMA_CHAN_EN); - - /* enable the DMA controller */ - dw_write(dma, DW_DMA_CFG, 1); - - /* mask all interrupts for all 8 channels */ - dw_write(dma, DW_MASK_TFR, INT_MASK_ALL); - dw_write(dma, DW_MASK_BLOCK, INT_MASK_ALL); - dw_write(dma, DW_MASK_SRC_TRAN, INT_MASK_ALL); - dw_write(dma, DW_MASK_DST_TRAN, INT_MASK_ALL); - dw_write(dma, DW_MASK_ERR, INT_MASK_ALL); - -#if CONFIG_DMA_FIFO_PARTITION - /* TODO: we cannot config DMA FIFOs if DMAC has been already */ - /* allocate FIFO partitions, 128 bytes for each ch */ - dw_write(dma, DW_FIFO_PART1_LO, 0x100080); - dw_write(dma, DW_FIFO_PART1_HI, 0x100080); - dw_write(dma, DW_FIFO_PART0_HI, 0x100080); - dw_write(dma, DW_FIFO_PART0_LO, 0x100080 | (1 << 26)); - dw_write(dma, DW_FIFO_PART0_LO, 0x100080); #endif - /* set channel priorities */ - for (i = 0; i < DW_MAX_CHAN; i++) { -#if CONFIG_BAYTRAIL || CONFIG_CHERRYTRAIL || \ - CONFIG_APOLLOLAKE || CONFIG_CANNONLAKE || \ - CONFIG_ICELAKE || CONFIG_SUECREEK - dw_write(dma, DW_CTRL_HIGH(i), - DW_CTLH_CLASS(dp->chan[i].class)); -#elif CONFIG_BROADWELL || CONFIG_HASWELL - dw_write(dma, DW_CFG_LOW(i), - DW_CFG_CLASS(dp->chan[i].class)); -#endif - } - - return 0; -} - static void dw_dma_verify_transfer(struct dma *dma, int channel, struct dma_sg_elem *next) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; + struct dw_dma_chan_data *chan = p->chan + channel; #if CONFIG_HW_LLI - struct dw_lli2 *ll_uncached = cache_to_uncache(chan->lli_current); + struct dw_lli *ll_uncached = cache_to_uncache(chan->lli_current); switch (next->size) { case DMA_RELOAD_END: chan->status = COMP_STATE_PREPARE; - dw_write(dma, DW_DMA_CHAN_EN, CHAN_DISABLE(channel)); + dw_write(dma, DW_DMA_CHAN_EN, DW_CHAN_MASK(channel)); /* fallthrough */ default: if (ll_uncached->ctrl_hi & DW_CTLH_DONE(1)) { ll_uncached->ctrl_hi &= ~DW_CTLH_DONE(1); chan->lli_current = - (struct dw_lli2 *)chan->lli_current->llp; + (struct dw_lli *)chan->lli_current->llp; } break; } @@ -1219,7 +981,7 @@ static void dw_dma_verify_transfer(struct dma *dma, int channel, switch (next->size) { case DMA_RELOAD_END: chan->status = COMP_STATE_PREPARE; - chan->lli_current = (struct dw_lli2 *)chan->lli_current->llp; + chan->lli_current = (struct dw_lli *)chan->lli_current->llp; break; case DMA_RELOAD_LLI: dw_dma_chan_reload_lli(dma, channel); @@ -1235,11 +997,12 @@ static void dw_dma_irq_callback(struct dma *dma, int channel, struct dma_sg_elem *next, uint32_t type) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = p->chan + channel; + struct dw_dma_chan_data *chan = p->chan + channel; - if (channel >= dma->plat_data.channels) { - trace_dwdma_error("dw-dma: %d invalid channel %d", - dma->plat_data.id, channel); + if (channel >= dma->plat_data.channels || + channel == DMA_CHAN_INVALID) { + trace_dwdma_error("dw_dma_irq_callback() error: dma %d invalid" + " channel %d", dma->plat_data.id, channel); return; } @@ -1253,15 +1016,15 @@ static void dw_dma_irq_callback(struct dma *dma, int channel, static int dw_dma_copy(struct dma *dma, int channel, int bytes, uint32_t flags) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = &p->chan[channel]; + struct dw_dma_chan_data *chan = p->chan + channel; struct dma_sg_elem next = { .src = DMA_RELOAD_LLI, .dest = DMA_RELOAD_LLI, .size = bytes }; - tracev_dwdma("dw-dma: %d channel %d copy", dma->plat_data.id, - channel); + tracev_dwdma("dw_dma_copy(): dma %d channel %d copy", + dma->plat_data.id, channel); dw_dma_irq_callback(dma, channel, &next, DMA_CB_TYPE_COPY); @@ -1390,6 +1153,54 @@ static inline void dw_dma_interrupt_unregister(struct dma *dma, int channel) #endif } +static int dw_dma_setup(struct dma *dma) +{ + int i; + + /* we cannot config DMAC if DMAC has been already enabled by host */ + if (dw_read(dma, DW_DMA_CFG)) + dw_write(dma, DW_DMA_CFG, 0); + + /* now check that it's 0 */ + for (i = DW_DMA_CFG_TRIES; i > 0; i--) + if (!dw_read(dma, DW_DMA_CFG)) + break; + + if (!i) { + trace_dwdma_error("dw_dma_setup(): dma %d setup failed", + dma->plat_data.id); + return -EIO; + } + + for (i = 0; i < DW_MAX_CHAN; i++) + dw_read(dma, DW_DMA_CHAN_EN); + + /* enable the DMA controller */ + dw_write(dma, DW_DMA_CFG, 1); + + /* mask all interrupts for all channels */ + dw_write(dma, DW_MASK_TFR, DW_CHAN_MASK_ALL); + dw_write(dma, DW_MASK_BLOCK, DW_CHAN_MASK_ALL); + dw_write(dma, DW_MASK_SRC_TRAN, DW_CHAN_MASK_ALL); + dw_write(dma, DW_MASK_DST_TRAN, DW_CHAN_MASK_ALL); + dw_write(dma, DW_MASK_ERR, DW_CHAN_MASK_ALL); + +#if CONFIG_DMA_FIFO_PARTITION + /* allocate FIFO partitions for each channel */ + dw_write(dma, DW_FIFO_PART1_HI, + DW_FIFO_CHx(DW_FIFO_SIZE) | DW_FIFO_CHy(DW_FIFO_SIZE)); + dw_write(dma, DW_FIFO_PART1_LO, + DW_FIFO_CHx(DW_FIFO_SIZE) | DW_FIFO_CHy(DW_FIFO_SIZE)); + dw_write(dma, DW_FIFO_PART0_HI, + DW_FIFO_CHx(DW_FIFO_SIZE) | DW_FIFO_CHy(DW_FIFO_SIZE)); + dw_write(dma, DW_FIFO_PART0_LO, + DW_FIFO_CHx(DW_FIFO_SIZE) | DW_FIFO_CHy(DW_FIFO_SIZE) | + DW_FIFO_UPD); +#endif + + return 0; +} + static int dw_dma_probe(struct dma *dma) { struct dma_pdata *dw_pdata; @@ -1406,8 +1217,8 @@ static int dw_dma_probe(struct dma *dma) dw_pdata = rzalloc(RZONE_SYS_RUNTIME | RZONE_FLAG_UNCACHED, SOF_MEM_CAPS_RAM, sizeof(*dw_pdata)); if (!dw_pdata) { - trace_error(TRACE_CLASS_DMA, "dw_dma_probe() error: " - "alloc failed"); + trace_dwdma_error("dw_dma_probe() error: dma %d alloc failed", + dma->plat_data.id); return -ENOMEM; } dma_set_drvdata(dma, dw_pdata); @@ -1430,7 +1241,8 @@ static int dw_dma_probe(struct dma *dma) static int dw_dma_remove(struct dma *dma) { - tracev_dwdma("dw_dma_remove() id = %u", dma->plat_data.id); + tracev_dwdma("dw_dma_remove(): dma %d remove", dma->plat_data.id); + pm_runtime_put_sync(DW_DMAC_CLK, dma->plat_data.id); rfree(dma_get_drvdata(dma)); dma_set_drvdata(dma, NULL); @@ -1440,7 +1252,7 @@ static int dw_dma_remove(struct dma *dma) static int dw_dma_avail_data_size(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = &p->chan[channel]; + struct dw_dma_chan_data *chan = p->chan + channel; int32_t read_ptr = chan->ptr_data.current_ptr; int32_t write_ptr = dw_read(dma, DW_DAR(channel)); int size; @@ -1455,7 +1267,7 @@ static int dw_dma_avail_data_size(struct dma *dma, int channel) static int dw_dma_free_data_size(struct dma *dma, int channel) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = &p->chan[channel]; + struct dw_dma_chan_data *chan = p->chan + channel; int32_t read_ptr = dw_read(dma, DW_SAR(channel)); int32_t write_ptr = chan->ptr_data.current_ptr; int size; @@ -1471,10 +1283,10 @@ static int dw_dma_get_data_size(struct dma *dma, int channel, uint32_t *avail, uint32_t *free) { struct dma_pdata *p = dma_get_drvdata(dma); - struct dma_chan_data *chan = &p->chan[channel]; + struct dw_dma_chan_data *chan = p->chan + channel; uint32_t flags; - tracev_dwdma("dw-dma: %d channel %d get_data_size", + tracev_dwdma("dw_dma_get_data_size(): dma %d channel %d get data size", dma->plat_data.id, channel); spin_lock_irq(&dma->lock, flags); @@ -1491,19 +1303,19 @@ static int dw_dma_get_data_size(struct dma *dma, int channel, uint32_t *avail, } const struct dma_ops dw_dma_ops = { - .channel_get = dw_dma_channel_get, - .channel_put = dw_dma_channel_put, - .start = dw_dma_start, - .stop = dw_dma_stop, - .pause = dw_dma_pause, - .release = dw_dma_release, - .copy = dw_dma_copy, - .status = dw_dma_status, - .set_config = dw_dma_set_config, - .set_cb = dw_dma_set_cb, - .pm_context_restore = dw_dma_pm_context_restore, - .pm_context_store = dw_dma_pm_context_store, - .probe = dw_dma_probe, - .remove = dw_dma_remove, - .get_data_size = dw_dma_get_data_size, + .channel_get = dw_dma_channel_get, + .channel_put = dw_dma_channel_put, + .start = dw_dma_start, + .stop = dw_dma_stop, + .pause = dw_dma_pause, + .release = dw_dma_release, + .copy = dw_dma_copy, + .status = dw_dma_status, + .set_config = dw_dma_set_config, + .set_cb = dw_dma_set_cb, + .pm_context_restore = dw_dma_pm_context_restore, + .pm_context_store = dw_dma_pm_context_store, + .probe = dw_dma_probe, + .remove = dw_dma_remove, + .get_data_size = dw_dma_get_data_size, }; diff --git a/src/include/sof/dw-dma.h b/src/include/sof/dw-dma.h index 2517fb10f985..853e6bc010ad 100644 --- a/src/include/sof/dw-dma.h +++ b/src/include/sof/dw-dma.h @@ -32,9 +32,126 @@ #ifndef __SOF_DW_DMA_H__ #define __SOF_DW_DMA_H__ +#include +#include #include -#define DW_DMA_MAX_NR_CHANNELS 8 +/* channel registers */ +#define DW_MAX_CHAN 8 +#define DW_FIFO_SIZE 0x80 +#define DW_CHAN_SIZE 0x58 +#define DW_CHAN_OFFSET(chan) (DW_CHAN_SIZE * (chan)) + +#define DW_SAR(chan) (0x00 + DW_CHAN_OFFSET(chan)) +#define DW_DAR(chan) (0x08 + DW_CHAN_OFFSET(chan)) +#define DW_LLP(chan) (0x10 + DW_CHAN_OFFSET(chan)) +#define DW_CTRL_LOW(chan) (0x18 + DW_CHAN_OFFSET(chan)) +#define DW_CTRL_HIGH(chan) (0x1C + DW_CHAN_OFFSET(chan)) +#define DW_CFG_LOW(chan) (0x40 + DW_CHAN_OFFSET(chan)) +#define DW_CFG_HIGH(chan) (0x44 + DW_CHAN_OFFSET(chan)) +#define DW_DSR(chan) (0x50 + DW_CHAN_OFFSET(chan)) + +/* common registers */ +#define DW_RAW_TFR 0x2C0 +#define DW_RAW_BLOCK 0x2C8 +#define DW_RAW_SRC_TRAN 0x2D0 +#define DW_RAW_DST_TRAN 0x2D8 +#define DW_RAW_ERR 0x2E0 +#define DW_STATUS_TFR 0x2E8 +#define DW_STATUS_BLOCK 0x2F0 +#define DW_STATUS_SRC_TRAN 0x2F8 +#define DW_STATUS_DST_TRAN 0x300 +#define DW_STATUS_ERR 0x308 +#define DW_MASK_TFR 0x310 +#define DW_MASK_BLOCK 0x318 +#define DW_MASK_SRC_TRAN 0x320 +#define DW_MASK_DST_TRAN 0x328 +#define DW_MASK_ERR 0x330 +#define DW_CLEAR_TFR 0x338 +#define DW_CLEAR_BLOCK 0x340 +#define DW_CLEAR_SRC_TRAN 0x348 +#define DW_CLEAR_DST_TRAN 0x350 +#define DW_CLEAR_ERR 0x358 +#define DW_INTR_STATUS 0x360 +#define DW_DMA_CFG 0x398 +#define DW_DMA_CHAN_EN 0x3A0 +#define DW_FIFO_PART0_LO 0x400 +#define DW_FIFO_PART0_HI 0x404 +#define DW_FIFO_PART1_LO 0x408 +#define DW_FIFO_PART1_HI 0x40C + +/* channel bits */ +#define DW_CHAN_WRITE_EN_ALL MASK(2 * DW_MAX_CHAN - 1, DW_MAX_CHAN) +#define DW_CHAN_WRITE_EN(chan) BIT((chan) + DW_MAX_CHAN) +#define DW_CHAN_ALL MASK(DW_MAX_CHAN - 1, 0) +#define DW_CHAN(chan) BIT(chan) +#define DW_CHAN_MASK_ALL DW_CHAN_WRITE_EN_ALL +#define DW_CHAN_MASK(chan) DW_CHAN_WRITE_EN(chan) +#define DW_CHAN_UNMASK_ALL (DW_CHAN_WRITE_EN_ALL | DW_CHAN_ALL) +#define DW_CHAN_UNMASK(chan) (DW_CHAN_WRITE_EN(chan) | DW_CHAN(chan)) + +/* CFG_LO */ +#define DW_CFGL_DRAIN BIT(10) +#define DW_CFGL_FIFO_EMPTY BIT(9) +#define DW_CFGL_SUSPEND BIT(8) + +/* CTL_LO */ +#define DW_CTLL_RELOAD_DST BIT(31) +#define DW_CTLL_RELOAD_SRC BIT(30) +#define DW_CTLL_LLP_S_EN BIT(28) +#define DW_CTLL_LLP_D_EN BIT(27) +#define DW_CTLL_SMS(x) SET_BIT(25, x) +#define DW_CTLL_DMS(x) SET_BIT(23, x) +#define DW_CTLL_FC_P2P SET_BITS(21, 20, 3) +#define DW_CTLL_FC_P2M SET_BITS(21, 20, 2) +#define DW_CTLL_FC_M2P SET_BITS(21, 20, 1) +#define DW_CTLL_FC_M2M SET_BITS(21, 20, 0) +#define DW_CTLL_D_SCAT_EN BIT(18) +#define DW_CTLL_S_GATH_EN BIT(17) +#define DW_CTLL_SRC_MSIZE(x) SET_BITS(16, 14, x) +#define DW_CTLL_DST_MSIZE(x) SET_BITS(13, 11, x) +#define DW_CTLL_SRC_FIX SET_BITS(10, 9, 2) +#define DW_CTLL_SRC_DEC SET_BITS(10, 9, 1) +#define DW_CTLL_SRC_INC SET_BITS(10, 9, 0) +#define DW_CTLL_DST_FIX SET_BITS(8, 7, 2) +#define DW_CTLL_DST_DEC SET_BITS(8, 7, 1) +#define DW_CTLL_DST_INC SET_BITS(8, 7, 0) +#define DW_CTLL_SRC_WIDTH(x) SET_BITS(6, 4, x) +#define DW_CTLL_DST_WIDTH(x) SET_BITS(3, 1, x) +#define DW_CTLL_INT_EN BIT(0) +#define DW_CTLL_SRC_WIDTH_MASK MASK(6, 4) +#define DW_CTLL_SRC_WIDTH_SHIFT 4 +#define DW_CTLL_DST_WIDTH_MASK MASK(3, 1) +#define DW_CTLL_DST_WIDTH_SHIFT 1 + +/* DSR */ +#define DW_DSR_DSC(x) SET_BITS(31, 20, x) +#define DW_DSR_DSI(x) SET_BITS(19, 0, x) + +/* FIFO_PART */ +#define DW_FIFO_UPD BIT(26) +#define DW_FIFO_CHx(x) SET_BITS(25, 13, x) +#define DW_FIFO_CHy(x) SET_BITS(12, 0, x) + +/* number of tries to wait for reset */ +#define DW_DMA_CFG_TRIES 10000 + +/* min number of elems for config with irq disabled */ +#define DW_DMA_CFG_NO_IRQ_MIN_ELEMS 3 + +/* linked list item address */ +#define DW_DMA_LLI_ADDRESS(lli, dir) \ + (((dir) == DMA_DIR_MEM_TO_DEV) ? ((lli)->sar) : ((lli)->dar)) + +/* tracing */ +#define trace_dwdma(__e, ...) \ + trace_event(TRACE_CLASS_DMA, __e, ##__VA_ARGS__) +#define trace_dwdma_atomic(__e, ...) \ + trace_event_atomic(TRACE_CLASS_DMA, __e, ##__VA_ARGS__) +#define tracev_dwdma(__e, ...) \ + tracev_event(TRACE_CLASS_DMA, __e, ##__VA_ARGS__) +#define trace_dwdma_error(__e, ...) \ + trace_error(TRACE_CLASS_DMA, __e, ##__VA_ARGS__) /* TODO: add FIFO sizes */ struct dw_chan_data { @@ -43,20 +160,11 @@ struct dw_chan_data { }; struct dw_drv_plat_data { - struct dw_chan_data chan[DW_DMA_MAX_NR_CHANNELS]; + struct dw_chan_data chan[DW_MAX_CHAN]; }; -/* DMA descriptor used by the HW version 1 */ -struct dw_lli1 { - uint32_t sar; - uint32_t dar; - uint32_t llp; - uint32_t ctrl_lo; - uint32_t ctrl_hi; -} __attribute__ ((packed)); - -/* DMA descriptor used by HW version 2 */ -struct dw_lli2 { +/* DMA descriptor used by HW */ +struct dw_lli { uint32_t sar; uint32_t dar; uint32_t llp; diff --git a/src/platform/apollolake/include/platform/dw-dma.h b/src/platform/apollolake/include/platform/dw-dma.h new file mode 100644 index 000000000000..ae6164d5cc9d --- /dev/null +++ b/src/platform/apollolake/include/platform/dw-dma.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Tomasz Lauda + */ + +#ifndef __INCLUDE_PLATFORM_DW_DMA_H__ +#define __INCLUDE_PLATFORM_DW_DMA_H__ + +#include + +#endif diff --git a/src/platform/baytrail/include/platform/dw-dma.h b/src/platform/baytrail/include/platform/dw-dma.h new file mode 100644 index 000000000000..55b6122549c7 --- /dev/null +++ b/src/platform/baytrail/include/platform/dw-dma.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Tomasz Lauda + */ + +#ifndef __INCLUDE_PLATFORM_DW_DMA_H__ +#define __INCLUDE_PLATFORM_DW_DMA_H__ + +#include + +/* CTL_HI */ +#define DW_CTLH_CLASS(x) SET_BITS(31, 29, x) +#define DW_CTLH_WEIGHT(x) SET_BITS(28, 18, x) +#define DW_CTLH_DONE(x) SET_BIT(17, x) +#define DW_CTLH_BLOCK_TS_MASK MASK(16, 0) + +/* CFG_HI */ +#define DW_CFGH_DST_PER(x) SET_BITS(7, 4, x) +#define DW_CFGH_SRC_PER(x) SET_BITS(3, 0, x) +#define DW_CFGH_DST(x) DW_CFGH_DST_PER(x) +#define DW_CFGH_SRC(x) DW_CFGH_SRC_PER(x) + +/* default initial setup register values */ +#define DW_CFG_LOW_DEF 0x3 +#define DW_CFG_HIGH_DEF 0x0 + +#define platform_dw_dma_set_class(chan, lli, class) \ + (lli->ctrl_hi |= DW_CTLH_CLASS(class)) + +#define platform_dw_dma_set_transfer_size(chan, lli, size) \ + (lli->ctrl_hi |= (size & DW_CTLH_BLOCK_TS_MASK)) + +#endif diff --git a/src/platform/cannonlake/include/platform/dw-dma.h b/src/platform/cannonlake/include/platform/dw-dma.h new file mode 100644 index 000000000000..ae6164d5cc9d --- /dev/null +++ b/src/platform/cannonlake/include/platform/dw-dma.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Tomasz Lauda + */ + +#ifndef __INCLUDE_PLATFORM_DW_DMA_H__ +#define __INCLUDE_PLATFORM_DW_DMA_H__ + +#include + +#endif diff --git a/src/platform/haswell/include/platform/dw-dma.h b/src/platform/haswell/include/platform/dw-dma.h new file mode 100644 index 000000000000..d6d2bd160320 --- /dev/null +++ b/src/platform/haswell/include/platform/dw-dma.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Tomasz Lauda + */ + +#ifndef __INCLUDE_PLATFORM_DW_DMA_H__ +#define __INCLUDE_PLATFORM_DW_DMA_H__ + +#include + +/* CTL_HI */ +#define DW_CTLH_DONE(x) SET_BIT(12, x) +#define DW_CTLH_BLOCK_TS_MASK MASK(11, 0) + +/* CFG_LO */ +#define DW_CFGL_CLASS(x) SET_BITS(7, 5, x) + +/* CFG_HI */ +#define DW_CFGH_DST_PER(x) SET_BITS(14, 11, x) +#define DW_CFGH_SRC_PER(x) SET_BITS(10, 7, x) +#define DW_CFGH_DST(x) DW_CFGH_DST_PER(x) +#define DW_CFGH_SRC(x) DW_CFGH_SRC_PER(x) + +/* default initial setup register values */ +#define DW_CFG_LOW_DEF 0x0 +#define DW_CFG_HIGH_DEF 0x4 + +#define platform_dw_dma_set_class(chan, lli, class) \ + (chan->cfg_lo |= DW_CFGL_CLASS(class)) + +#define platform_dw_dma_set_transfer_size(chan, lli, size) \ + (lli->ctrl_hi |= ((size / (1 << ((lli->ctrl_lo & \ + DW_CTLL_SRC_WIDTH_MASK) >> DW_CTLL_SRC_WIDTH_SHIFT))) & \ + DW_CTLH_BLOCK_TS_MASK)) + +#endif diff --git a/src/platform/icelake/include/platform/dw-dma.h b/src/platform/icelake/include/platform/dw-dma.h new file mode 100644 index 000000000000..ae6164d5cc9d --- /dev/null +++ b/src/platform/icelake/include/platform/dw-dma.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Tomasz Lauda + */ + +#ifndef __INCLUDE_PLATFORM_DW_DMA_H__ +#define __INCLUDE_PLATFORM_DW_DMA_H__ + +#include + +#endif diff --git a/src/platform/intel/cavs/include/cavs/dw-dma.h b/src/platform/intel/cavs/include/cavs/dw-dma.h new file mode 100644 index 000000000000..10fb61399bc7 --- /dev/null +++ b/src/platform/intel/cavs/include/cavs/dw-dma.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Tomasz Lauda + */ + +#ifndef __INCLUDE_CAVS_DW_DMA_H__ +#define __INCLUDE_CAVS_DW_DMA_H__ + +#include + +/* CTL_HI */ +#define DW_CTLH_CLASS(x) SET_BITS(31, 29, x) +#define DW_CTLH_WEIGHT(x) SET_BITS(28, 18, x) +#define DW_CTLH_DONE(x) SET_BIT(17, x) +#define DW_CTLH_BLOCK_TS_MASK MASK(16, 0) + +/* CFG_LO */ +#define DW_CFG_RELOAD_DST BIT(31) +#define DW_CFG_RELOAD_SRC BIT(30) +#define DW_CFG_CTL_HI_UPD_EN BIT(5) + +/* CFG_HI */ +#define DW_CFGH_DST_PER_EXT(x) SET_BITS(31, 30, x) +#define DW_CFGH_SRC_PER_EXT(x) SET_BITS(29, 28, x) +#define DW_CFGH_DST_PER(x) SET_BITS(7, 4, x) +#define DW_CFGH_SRC_PER(x) SET_BITS(3, 0, x) +#define DW_CFGH_DST(x) \ + (DW_CFGH_DST_PER_EXT((x) & 0x30) | DW_CFGH_DST_PER((x) & 0xF)) +#define DW_CFGH_SRC(x) \ + (DW_CFGH_SRC_PER_EXT((x) & 0x30) | DW_CFGH_SRC_PER((x) & 0xF)) + +/* default initial setup register values */ +#define DW_CFG_LOW_DEF 0x3 +#define DW_CFG_HIGH_DEF 0x0 + +#define platform_dw_dma_set_class(chan, lli, class) \ + (lli->ctrl_hi |= DW_CTLH_CLASS(class)) + +#define platform_dw_dma_set_transfer_size(chan, lli, size) \ + (lli->ctrl_hi |= (size & DW_CTLH_BLOCK_TS_MASK)) + +#endif diff --git a/src/platform/suecreek/include/platform/dw-dma.h b/src/platform/suecreek/include/platform/dw-dma.h new file mode 100644 index 000000000000..ae6164d5cc9d --- /dev/null +++ b/src/platform/suecreek/include/platform/dw-dma.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Tomasz Lauda + */ + +#ifndef __INCLUDE_PLATFORM_DW_DMA_H__ +#define __INCLUDE_PLATFORM_DW_DMA_H__ + +#include + +#endif