[Sound-open-firmware] [PATCH] drivers: dw-dma: move register macros into platform specific header.
Clean up the DW-DMA rsgisters so that it can be more easily integrated into other platforms.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/drivers/dw-dma.c | 106 ++++++++++++++++++--------- src/platform/baytrail/include/platform/dma.h | 26 +++++++ 2 files changed, 99 insertions(+), 33 deletions(-)
diff --git a/src/drivers/dw-dma.c b/src/drivers/dw-dma.c index 16f59d1..e851e54 100644 --- a/src/drivers/dw-dma.c +++ b/src/drivers/dw-dma.c @@ -62,6 +62,7 @@ #include <errno.h> #include <stdint.h> #include <string.h> +#include <config.h>
/* channel registers */ #define DW_MAX_CHAN 8 @@ -108,20 +109,16 @@ #define DW_INTR_STATUS 0x0360 #define DW_DMA_CFG 0x0398 #define DW_DMA_CHAN_EN 0x03A0 -#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
/* 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 DW_CFG_CH_SUSPEND 0x100 -#define DW_CFG_CH_DRAIN 0x400 #define DW_CFG_CH_FIFO_EMPTY 0x200
/* CTL_LO */ @@ -136,8 +133,6 @@ #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_S_GATH_EN (1 << 17) -#define DW_CTLL_D_SCAT_EN (1 << 18) #define DW_CTLL_FC(x) (x << 20) #define DW_CTLL_FC_M2M (0 << 20) #define DW_CTLL_FC_M2P (1 << 20) @@ -150,16 +145,6 @@ #define DW_CTLL_RELOAD_SRC (1 << 30) #define DW_CTLL_RELOAD_DST (1 << 31)
-/* CTL_HI */ -#define DW_CTLH_DONE 0x00020000 -#define DW_CTLH_BLOCK_TS_MASK 0x0001ffff -#define DW_CTLH_CLASS(x) (x << 29) -#define DW_CTLH_WEIGHT(x) (x << 18) - -/* CFG_HI */ -#define DW_CFGH_SRC_PER(x) (x << 0) -#define DW_CFGH_DST_PER(x) (x << 4) - /* tracing */ #define trace_dma(__e) trace_event(TRACE_CLASS_DMA, __e) #define trace_dma_error(__e) trace_error(TRACE_CLASS_DMA, __e) @@ -168,6 +153,9 @@ /* HW Linked list support currently disabled - needs debug for missing IRQs !!! */ #define DW_USE_HW_LLI 0
+/* number of tries to wait for reset */ +#define DW_DMA_CFG_TRIES 10000 + /* data for each DMA channel */ struct dma_chan_data { uint32_t status; @@ -264,7 +252,7 @@ static void dw_dma_channel_put_unlocked(struct dma *dma, int channel) return; }
- +#ifdef DW_CFG_CH_DRAIN /* have drain feature */ if (p->chan[channel].status == DMA_STATUS_PAUSED) {
dw_update_bits(dma, DW_CFG_LOW(channel), @@ -276,6 +264,7 @@ static void dw_dma_channel_put_unlocked(struct dma *dma, int channel) work_schedule_default(&p->chan[channel].work, 100); return; } +#endif
/* mask block, transfer and error interrupts for channel */ dw_write(dma, DW_MASK_TFR, INT_MASK(channel)); @@ -456,8 +445,11 @@ static uint32_t dw_dma_fifo_work(void *data, uint32_t udelay)
/* clear suspend */ dw_update_bits(dma, DW_CFG_LOW(cd->channel), +#ifdef DW_CFG_CH_DRAIN /* have drain feature */ DW_CFG_CH_SUSPEND | DW_CFG_CH_DRAIN, 0); - +#else + DW_CFG_CH_SUSPEND, 0); +#endif cd->status = DMA_STATUS_IDLE; goto out; } @@ -470,8 +462,11 @@ static uint32_t dw_dma_fifo_work(void *data, uint32_t udelay)
/* clear suspend */ dw_update_bits(dma, DW_CFG_LOW(cd->channel), +#ifdef DW_CFG_CH_DRAIN /* have drain feature */ DW_CFG_CH_SUSPEND | DW_CFG_CH_DRAIN, 0); - +#else + DW_CFG_CH_SUSPEND, 0); +#endif /* do we need to free it ? */ if (cd->status == DMA_STATUS_CLOSING) dw_dma_channel_put_unlocked(dma, cd->channel); @@ -512,15 +507,17 @@ static int dw_dma_stop(struct dma *dma, int channel, int drain) }
/* suspend and drain */ + bits = DW_CFG_CH_SUSPEND; + p->chan[channel].drain_count = 3; + p->chan[channel].status = DMA_STATUS_STOPPING; + +#ifdef DW_CFG_CH_DRAIN /* have drain feature, then may drain */ if (drain) { - bits = DW_CFG_CH_SUSPEND | DW_CFG_CH_DRAIN; + bits |= DW_CFG_CH_DRAIN; p->chan[channel].drain_count = 14; p->chan[channel].status = DMA_STATUS_DRAINING; - } else { - bits = DW_CFG_CH_SUSPEND; - p->chan[channel].drain_count = 3; - p->chan[channel].status = DMA_STATUS_STOPPING; } +#endif
dw_update_bits(dma, DW_CFG_LOW(channel), bits, bits); schedule = 1; @@ -568,8 +565,8 @@ static int dw_dma_set_config(struct dma *dma, int channel,
/* default channel config */ p->chan[channel].direction = config->direction; - p->chan[channel].cfg_lo = 0x00000003; - p->chan[channel].cfg_hi = 0x0; + p->chan[channel].cfg_lo = DW_CFG_LOW_DEF; + p->chan[channel].cfg_hi = DW_CFG_HIGH_DEF;
/* get number of SG elems */ list_for_item(plist, &config->elem_list) @@ -666,9 +663,19 @@ static int dw_dma_set_config(struct dma *dma, int channel, break; }
+ if (sg_elem->size > DW_CTLH_BLOCK_TS_MASK) { + trace_dma_error("eDS"); + return -EINVAL; + } /* set transfer size of element */ +#if defined CONFIG_BAYTRAIL || defined CONFIG_CHERRYTRAIL lli_desc->ctrl_hi = DW_CTLH_CLASS(p->class) | (sg_elem->size & DW_CTLH_BLOCK_TS_MASK); +#else + /* for 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
/* set next descriptor in list */ lli_desc->llp = (uint32_t)(lli_desc + 1); @@ -768,8 +775,14 @@ static inline void dw_dma_chan_reload_next(struct dma *dma, int channel, dw_write(dma, DW_DAR(channel), next->dest);
/* set transfer size of element */ +#if defined CONFIG_BAYTRAIL || defined CONFIG_CHERRYTRAIL lli->ctrl_hi = DW_CTLH_CLASS(p->class) | (next->size & DW_CTLH_BLOCK_TS_MASK); +#else + /* for the unit is transaction--TR_WIDTH. */ + lli->ctrl_hi = (next->size / (1 << (lli->ctrl_lo >> 4 & 0x7))) + & DW_CTLH_BLOCK_TS_MASK; +#endif
/* program CTLn */ dw_write(dma, DW_CTRL_LOW(channel), lli->ctrl_lo); @@ -872,16 +885,38 @@ static void 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) + goto found; + } + trace_dma_error("eDs"); + return; + +found: + 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);
/* mask all interrupts for all 8 channels */ - dw_write(dma, DW_MASK_TFR, 0x0000ff00); - dw_write(dma, DW_MASK_BLOCK, 0x0000ff00); - dw_write(dma, DW_MASK_SRC_TRAN, 0x0000ff00); - dw_write(dma, DW_MASK_DST_TRAN, 0x0000ff00); - dw_write(dma, DW_MASK_ERR, 0x0000ff00); + 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);
+#ifdef DW_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); @@ -889,10 +924,15 @@ static void dw_dma_setup(struct dma *dma) 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 defined CONFIG_BAYTRAIL || defined CONFIG_CHERRYTRAIL dw_write(dma, DW_CTRL_HIGH(i), DW_CTLH_CLASS(dp->chan[i].class)); +#else + dw_write(dma, DW_CFG_LOW(i), DW_CFG_CLASS(dp->chan[i].class)); +#endif }
} diff --git a/src/platform/baytrail/include/platform/dma.h b/src/platform/baytrail/include/platform/dma.h index eec501a..5f5c52a 100644 --- a/src/platform/baytrail/include/platform/dma.h +++ b/src/platform/baytrail/include/platform/dma.h @@ -38,6 +38,32 @@ #define DMA_ID_DMAC1 1 #define DMA_ID_DMAC2 2
+/* 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 0x00020000 +#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_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 + #define DMA_HANDSHAKE_SSP0_RX 0 #define DMA_HANDSHAKE_SSP0_TX 1 #define DMA_HANDSHAKE_SSP1_RX 2
Move the register macros into separate header.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/drivers/ssp.c | 113 ---------------------------------------------- src/include/reef/ssp.h | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 113 deletions(-)
diff --git a/src/drivers/ssp.c b/src/drivers/ssp.c index 6ef5e26..4f375e5 100644 --- a/src/drivers/ssp.c +++ b/src/drivers/ssp.c @@ -30,129 +30,16 @@ */
#include <errno.h> -#include <reef/dai.h> -#include <reef/io.h> #include <reef/stream.h> #include <reef/ssp.h> #include <reef/alloc.h> #include <reef/interrupt.h> -#include <reef/lock.h> -#include <reef/work.h> -#include <reef/trace.h> -#include <reef/wait.h> - -/* SSCR0 bits */ -#define SSCR0_DSS_MASK (0x0000000f) -#define SSCR0_DSIZE(x) ((x) - 1) -#define SSCR0_FRF (0x00000030) -#define SSCR0_MOT (00 << 4) -#define SSCR0_TI (1 << 4) -#define SSCR0_NAT (2 << 4) -#define SSCR0_PSP (3 << 4) -#define SSCR0_ECS (1 << 6) -#define SSCR0_SSE (1 << 7) -#define SSCR0_SCR(x) ((x) << 8) -#define SSCR0_EDSS (1 << 20) -#define SSCR0_NCS (1 << 21) -#define SSCR0_RIM (1 << 22) -#define SSCR0_TUM (1 << 23) -#define SSCR0_FRDC (0x07000000) -#define SSCR0_ACS (1 << 30) -#define SSCR0_MOD (1 << 31) - -/* SSCR1 bits */ -#define SSCR1_RIE (1 << 0) -#define SSCR1_TIE (1 << 1) -#define SSCR1_LBM (1 << 2) -#define SSCR1_SPO (1 << 3) -#define SSCR1_SPH (1 << 4) -#define SSCR1_MWDS (1 << 5) -#define SSCR1_TFT_MASK (0x000003c0) -#define SSCR1_TX(x) (((x) - 1) << 6) -#define SSCR1_RFT_MASK (0x00003c00) -#define SSCR1_RX(x) (((x) - 1) << 10) -#define SSCR1_EFWR (1 << 14) -#define SSCR1_STRF (1 << 15) -#define SSCR1_IFS (1 << 16) -#define SSCR1_PINTE (1 << 18) -#define SSCR1_TINTE (1 << 19) -#define SSCR1_RSRE (1 << 20) -#define SSCR1_TSRE (1 << 21) -#define SSCR1_TRAIL (1 << 22) -#define SSCR1_RWOT (1 << 23) -#define SSCR1_SFRMDIR (1 << 24) -#define SSCR1_SCLKDIR (1 << 25) -#define SSCR1_ECRB (1 << 26) -#define SSCR1_ECRA (1 << 27) -#define SSCR1_SCFR (1 << 28) -#define SSCR1_EBCEI (1 << 29) -#define SSCR1_TTE (1 << 30) -#define SSCR1_TTELP (1 << 31) - -/* SSR bits */ -#define SSSR_TNF (1 << 2) -#define SSSR_RNE (1 << 3) -#define SSSR_BSY (1 << 4) -#define SSSR_TFS (1 << 5) -#define SSSR_RFS (1 << 6) -#define SSSR_ROR (1 << 7) - -/* SSPSP bits */ -#define SSPSP_SCMODE(x) ((x) << 0) -#define SSPSP_SFRMP (1 << 2) -#define SSPSP_ETDS (1 << 3) -#define SSPSP_STRTDLY(x) ((x) << 4) -#define SSPSP_DMYSTRT(x) ((x) << 7) -#define SSPSP_SFRMDLY(x) ((x) << 9) -#define SSPSP_SFRMWDTH(x) ((x) << 16) -#define SSPSP_DMYSTOP(x) ((x) << 23) -#define SSPSP_FSRT (1 << 25) - -/* SFIFOTT bits */ -#define SFIFOTT_TX(x) (x - 1) -#define SFIFOTT_RX(x) ((x - 1) << 16) - -/* SSP port status */ -#define SSP_STATE_INIT 0 -#define SSP_STATE_IDLE 1 -#define SSP_STATE_RUNNING 2 -#define SSP_STATE_DRAINING 3 -#define SSP_STATE_PAUSING 4 -#define SSP_STATE_PAUSED 5
/* tracing */ #define trace_ssp(__e) trace_event(TRACE_CLASS_SSP, __e) #define trace_ssp_error(__e) trace_error(TRACE_CLASS_SSP, __e) #define tracev_ssp(__e) tracev_event(TRACE_CLASS_SSP, __e)
-/* SSP private data */ -struct ssp_pdata { - uint32_t sscr0; - uint32_t sscr1; - uint32_t psp; - struct work work; - spinlock_t lock; - uint32_t state[2]; /* SSP_STATE_ for each direction */ - completion_t drain_complete; - -}; - -static inline void ssp_write(struct dai *dai, uint32_t reg, uint32_t value) -{ - io_reg_write(dai_base(dai) + reg, value); -} - -static inline uint32_t ssp_read(struct dai *dai, uint32_t reg) -{ - return io_reg_read(dai_base(dai) + reg); -} - -static inline void ssp_update_bits(struct dai *dai, uint32_t reg, uint32_t mask, - uint32_t value) -{ - io_reg_update_bits(dai_base(dai) + reg, mask, value); -} - /* save SSP context prior to entering D3 */ static int ssp_context_store(struct dai *dai) { diff --git a/src/include/reef/ssp.h b/src/include/reef/ssp.h index 16acf04..b1f370b 100644 --- a/src/include/reef/ssp.h +++ b/src/include/reef/ssp.h @@ -32,6 +32,11 @@ #define __INCLUDE_SSP__
#include <reef/dai.h> +#include <reef/io.h> +#include <reef/lock.h> +#include <reef/work.h> +#include <reef/trace.h> +#include <reef/wait.h>
#define SSP_CLK_AUDIO 0 #define SSP_CLK_NET_PLL 1 @@ -54,4 +59,117 @@
extern const struct dai_ops ssp_ops;
+/* SSCR0 bits */ +#define SSCR0_DSS_MASK (0x0000000f) +#define SSCR0_DSIZE(x) ((x) - 1) +#define SSCR0_FRF (0x00000030) +#define SSCR0_MOT (00 << 4) +#define SSCR0_TI (1 << 4) +#define SSCR0_NAT (2 << 4) +#define SSCR0_PSP (3 << 4) +#define SSCR0_ECS (1 << 6) +#define SSCR0_SSE (1 << 7) +#define SSCR0_SCR_MASK (0x000fff00) +#define SSCR0_SCR(x) ((x) << 8) +#define SSCR0_EDSS (1 << 20) +#define SSCR0_NCS (1 << 21) +#define SSCR0_RIM (1 << 22) +#define SSCR0_TUM (1 << 23) +#define SSCR0_FRDC (0x07000000) +#define SSCR0_ACS (1 << 30) +#define SSCR0_MOD (1 << 31) + +/* SSCR1 bits */ +#define SSCR1_RIE (1 << 0) +#define SSCR1_TIE (1 << 1) +#define SSCR1_LBM (1 << 2) +#define SSCR1_SPO (1 << 3) +#define SSCR1_SPH (1 << 4) +#define SSCR1_MWDS (1 << 5) +#define SSCR1_TFT_MASK (0x000003c0) +#define SSCR1_TX(x) (((x) - 1) << 6) +#define SSCR1_RFT_MASK (0x00003c00) +#define SSCR1_RX(x) (((x) - 1) << 10) +#define SSCR1_EFWR (1 << 14) +#define SSCR1_STRF (1 << 15) +#define SSCR1_IFS (1 << 16) +#define SSCR1_PINTE (1 << 18) +#define SSCR1_TINTE (1 << 19) +#define SSCR1_RSRE (1 << 20) +#define SSCR1_TSRE (1 << 21) +#define SSCR1_TRAIL (1 << 22) +#define SSCR1_RWOT (1 << 23) +#define SSCR1_SFRMDIR (1 << 24) +#define SSCR1_SCLKDIR (1 << 25) +#define SSCR1_ECRB (1 << 26) +#define SSCR1_ECRA (1 << 27) +#define SSCR1_SCFR (1 << 28) +#define SSCR1_EBCEI (1 << 29) +#define SSCR1_TTE (1 << 30) +#define SSCR1_TTELP (1 << 31) + +/* SSR bits */ +#define SSSR_TNF (1 << 2) +#define SSSR_RNE (1 << 3) +#define SSSR_BSY (1 << 4) +#define SSSR_TFS (1 << 5) +#define SSSR_RFS (1 << 6) +#define SSSR_ROR (1 << 7) + +/* SSPSP bits */ +#define SSPSP_SCMODE(x) ((x) << 0) +#define SSPSP_SFRMP (1 << 2) +#define SSPSP_ETDS (1 << 3) +#define SSPSP_STRTDLY(x) ((x) << 4) +#define SSPSP_DMYSTRT(x) ((x) << 7) +#define SSPSP_SFRMDLY(x) ((x) << 9) +#define SSPSP_SFRMWDTH(x) ((x) << 16) +#define SSPSP_DMYSTOP(x) ((x) << 23) +#define SSPSP_FSRT (1 << 25) + +/* SFIFOTT bits */ +#define SFIFOTT_TX(x) (x - 1) +#define SFIFOTT_RX(x) ((x - 1) << 16) + +/* SSP port status */ +#define SSP_STATE_INIT 0 +#define SSP_STATE_RUNNING 1 +#define SSP_STATE_IDLE 2 +#define SSP_STATE_DRAINING 3 +#define SSP_STATE_PAUSING 4 +#define SSP_STATE_PAUSED 5 + +/* tracing */ +#define trace_ssp(__e) trace_event(TRACE_CLASS_SSP, __e) +#define trace_ssp_error(__e) trace_error(TRACE_CLASS_SSP, __e) +#define tracev_ssp(__e) tracev_event(TRACE_CLASS_SSP, __e) + +/* SSP private data */ +struct ssp_pdata { + uint32_t sscr0; + uint32_t sscr1; + uint32_t psp; + struct work work; + spinlock_t lock; + uint32_t state[2]; /* SSP_STATE_ for each direction */ + completion_t drain_complete; +}; + +static inline void ssp_write(struct dai *dai, uint32_t reg, uint32_t value) +{ + io_reg_write(dai_base(dai) + reg, value); +} + +static inline uint32_t ssp_read(struct dai *dai, uint32_t reg) +{ + return io_reg_read(dai_base(dai) + reg); +} + +static inline void ssp_update_bits(struct dai *dai, uint32_t reg, uint32_t mask, + uint32_t value) +{ + io_reg_update_bits(dai_base(dai) + reg, mask, value); +} + + #endif
Also make sure the binaries have platform prefix.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/arch/xtensa/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/arch/xtensa/Makefile.am b/src/arch/xtensa/Makefile.am index c998c31..b9b1cc6 100644 --- a/src/arch/xtensa/Makefile.am +++ b/src/arch/xtensa/Makefile.am @@ -67,8 +67,8 @@ reef_LDFLAGS = \ -T ../../platform/$(PLATFORM)/$(PLATFORM_LDSCRIPT)
bin-local: reef - $(OBJCOPY) -O binary reef reef.bin - $(OBJDUMP) -D reef > reef-$(FW_NAME).map + $(OBJCOPY) -O binary reef reef-$(FW_NAME).bin + $(OBJDUMP) -h -D reef > reef-$(FW_NAME).map rimage -i reef -o reef-$(FW_NAME).ri -m $(FW_NAME)
vminstall-local:
Provide a method for tasks to be performed on a priority basis using the interrupts levels to preempt lower priority tasks.
The scheduler will use the to schedule work at different priorities.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/arch/xtensa/Makefile.am | 5 +- src/arch/xtensa/include/Makefile.am | 3 +- src/arch/xtensa/include/arch/task.h | 41 +++++++ src/arch/xtensa/init.c | 2 + src/arch/xtensa/task.c | 140 ++++++++++++++++++++++ src/platform/baytrail/include/platform/platform.h | 4 + 6 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 src/arch/xtensa/include/arch/task.h create mode 100644 src/arch/xtensa/task.c
diff --git a/src/arch/xtensa/Makefile.am b/src/arch/xtensa/Makefile.am index b9b1cc6..6670ef2 100644 --- a/src/arch/xtensa/Makefile.am +++ b/src/arch/xtensa/Makefile.am @@ -32,7 +32,8 @@ reef_SOURCES = \ _vectors.S \ init.c \ wait.S \ - timer.c + timer.c \ + task.c
reef_CFLAGS = \ $(ARCH_INCDIR) \ @@ -49,9 +50,9 @@ reef_LDADD = \ ../../init/libinit.a \ ../../platform/$(PLATFORM)/libplatform.a \ ../../tasks/libtasks.a \ - ../../audio/libaudio.a \ ../../lib/libcore.a \ ../../ipc/libipc.a \ + ../../audio/libaudio.a \ ../../drivers/libdrivers.a \ libreset.a \ xtos/libxtos.a \ diff --git a/src/arch/xtensa/include/Makefile.am b/src/arch/xtensa/include/Makefile.am index 96481b6..f114582 100644 --- a/src/arch/xtensa/include/Makefile.am +++ b/src/arch/xtensa/include/Makefile.am @@ -8,4 +8,5 @@ noinst_HEADERS = \ arch/interrupt.h \ arch/reef.h \ arch/spinlock.h \ - arch/timer.h + arch/timer.h \ + arch/task.h diff --git a/src/arch/xtensa/include/arch/task.h b/src/arch/xtensa/include/arch/task.h new file mode 100644 index 0000000..1547751 --- /dev/null +++ b/src/arch/xtensa/include/arch/task.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, 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: Liam Girdwood liam.r.girdwood@linux.intel.com + * + */ + +#ifndef __ARCH_TASK_H_ +#define __ARCH_TASK_H_ + +struct task; + +void arch_run_task(struct task *task); + +int arch_init_tasks(void); + +#endif diff --git a/src/arch/xtensa/init.c b/src/arch/xtensa/init.c index f904738..1e52d99 100644 --- a/src/arch/xtensa/init.c +++ b/src/arch/xtensa/init.c @@ -34,6 +34,7 @@ #include <reef/interrupt.h> #include <platform/interrupt.h> #include <reef/mailbox.h> +#include <arch/task.h> #include <reef/debug.h> #include <reef/init.h> #include <stdint.h> @@ -152,6 +153,7 @@ static void register_exceptions(void) int arch_init(struct reef *reef) { register_exceptions(); + arch_init_tasks(); return 0; }
diff --git a/src/arch/xtensa/task.c b/src/arch/xtensa/task.c new file mode 100644 index 0000000..7e74c07 --- /dev/null +++ b/src/arch/xtensa/task.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2017, 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: Liam Girdwood liam.r.girdwood@linux.intel.com + * + */ + +#include <reef/schedule.h> +#include <reef/interrupt.h> +#include <platform/platform.h> +#include <reef/debug.h> +#include <stdint.h> +#include <errno.h> + +static struct task *_irq_low_task = NULL; +static struct task *_irq_med_task = NULL; +static struct task *_irq_high_task = NULL; + +static inline uint32_t task_get_irq(struct task *task) +{ + uint32_t irq; + + switch (task->priority) { + case TASK_PRI_MED + 1 ... TASK_PRI_LOW: + irq = PLATFORM_IRQ_TASK_LOW; + break; + case TASK_PRI_HIGH ... TASK_PRI_MED - 1: + irq = PLATFORM_IRQ_TASK_HIGH; + break; + case TASK_PRI_MED: + default: + irq = PLATFORM_IRQ_TASK_MED; + break; + } + + return irq; +} + +static inline void task_set_data(struct task *task) +{ + switch (task->priority) { + case TASK_PRI_MED + 1 ... TASK_PRI_LOW: + _irq_low_task = task; + break; + case TASK_PRI_HIGH ... TASK_PRI_MED - 1: + _irq_high_task = task; + break; + case TASK_PRI_MED: + default: + _irq_med_task = task; + break; + } +} + +static void _irq_low(void *arg) +{ + struct task *task = *(struct task **)arg; + uint32_t irq; + + if (task->func) + task->func(task->data); + + schedule_task_complete(task); + irq = task_get_irq(task); + interrupt_clear(irq); +} + +static void _irq_med(void *arg) +{ + struct task *task = *(struct task **)arg; + uint32_t irq; + + if (task->func) + task->func(task->data); + + schedule_task_complete(task); + irq = task_get_irq(task); + interrupt_clear(irq); +} + +static void _irq_high(void *arg) +{ + struct task *task = *(struct task **)arg; + uint32_t irq; + + if (task->func) + task->func(task->data); + + schedule_task_complete(task); + irq = task_get_irq(task); + interrupt_clear(irq); +} + +/* architecture specific method of running task */ +void arch_run_task(struct task *task) +{ + uint32_t irq; + + task_set_data(task); + irq = task_get_irq(task); + interrupt_set(irq); +} + +int arch_init_tasks(void) +{ + interrupt_register(PLATFORM_IRQ_TASK_LOW, _irq_low, &_irq_low_task); + interrupt_enable(PLATFORM_IRQ_TASK_LOW); + + interrupt_register(PLATFORM_IRQ_TASK_MED, _irq_med, &_irq_med_task); + interrupt_enable(PLATFORM_IRQ_TASK_MED); + + interrupt_register(PLATFORM_IRQ_TASK_HIGH, _irq_high, &_irq_high_task); + interrupt_enable(PLATFORM_IRQ_TASK_HIGH); + + return 0; +} diff --git a/src/platform/baytrail/include/platform/platform.h b/src/platform/baytrail/include/platform/platform.h index cd1e1d9..3cc19cc 100644 --- a/src/platform/baytrail/include/platform/platform.h +++ b/src/platform/baytrail/include/platform/platform.h @@ -52,6 +52,10 @@ struct reef; /* pipeline IRQ */ #define PLATFORM_PIPELINE_IRQ IRQ_NUM_SOFTWARE4
+#define PLATFORM_IRQ_TASK_HIGH IRQ_NUM_SOFTWARE4 +#define PLATFORM_IRQ_TASK_MED IRQ_NUM_SOFTWARE3 +#define PLATFORM_IRQ_TASK_LOW IRQ_NUM_SOFTWARE2 + /* DMA treats PHY addresses as host address unless within DSP region */ #define PLATFORM_HOST_DMA_MASK 0xFF000000
Add an Earliest Deadline First scheduler to perform scheduling of audio pipeline tasks based on task deadlines. i.e. the task with the earliest deadline will be scheduled so that it will complete and preempt other lower priority tasks before the deadline.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/include/reef/Makefile.am | 1 + src/include/reef/schedule.h | 90 +++++++++ src/init/init.c | 4 + src/lib/schedule.c | 219 ++++++++++++++++++++++ src/platform/baytrail/include/platform/platform.h | 4 + 5 files changed, 318 insertions(+) create mode 100644 src/include/reef/schedule.h create mode 100644 src/lib/schedule.c
diff --git a/src/include/reef/Makefile.am b/src/include/reef/Makefile.am index dcece5c..f690e2a 100644 --- a/src/include/reef/Makefile.am +++ b/src/include/reef/Makefile.am @@ -17,6 +17,7 @@ noinst_HEADERS = \ mailbox.h \ notifier.h \ reef.h \ + schedule.h \ ssp.h \ stream.h \ task.h \ diff --git a/src/include/reef/schedule.h b/src/include/reef/schedule.h new file mode 100644 index 0000000..dd20c65 --- /dev/null +++ b/src/include/reef/schedule.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017, 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: Liam Girdwood liam.r.girdwood@linux.intel.com + */ + +#ifndef __INCLUDE_REEF_SCHEDULE_H__ +#define __INCLUDE_REEF_SCHEDULE_H__ + +#include <stdint.h> +#include <stddef.h> +#include <errno.h> +#include <reef/reef.h> +#include <reef/lock.h> +#include <reef/list.h> + +struct reef; + +/* task states */ +#define TASK_STATE_INIT 0 +#define TASK_STATE_QUEUED 1 +#define TASK_STATE_RUNNING 2 +#define TASK_STATE_PREEMPTED 3 +#define TASK_STATE_COMPLETED 4 + +/* task priorities - values same as Linux processes, gives scope for future.*/ +#define TASK_PRI_LOW 19 +#define TASK_PRI_MED 0 +#define TASK_PRI_HIGH -20 + +struct task { + uint16_t core; /* core id to run on */ + int16_t priority; /* scheduling priority TASK_PRI_ */ + uint32_t deadline; /* scheduling deadline */ + uint32_t max_rtime; /* max time taken to run */ + uint32_t state; /* TASK_STATE_ */ + struct list_item list; /* list in scheduler */ + void *data; + void *sdata; + void (*func)(void *arg); +}; + +void schedule(void); + +void schedule_task(struct task *task, uint32_t deadline, uint16_t priority, + void *data); + +void schedule_task_core(struct task *task, uint32_t deadline, + uint16_t priority, uint16_t core, void *data); + +void schedule_task_complete(struct task *task); + +static inline void task_init(struct task *task, void (*func)(void *), + void *data) +{ + task->core = 0; + task->priority = TASK_PRI_MED; + task->state = TASK_STATE_INIT; + task->func = func; + task->data = data; + task->sdata = NULL; +} + +int scheduler_init(struct reef *reef); + +#endif diff --git a/src/init/init.c b/src/init/init.c index 029c20f..1dc1237 100644 --- a/src/init/init.c +++ b/src/init/init.c @@ -39,6 +39,7 @@ #include <reef/notifier.h> #include <reef/work.h> #include <reef/trace.h> +#include <reef/schedule.h> #include <platform/platform.h>
/* main firmware context */ @@ -67,6 +68,9 @@ int main(int argc, char *argv[]) trace_point(TRACE_BOOT_SYS_NOTE); init_system_notify(&reef);
+ trace_point(TRACE_BOOT_SYS_SCHED); + scheduler_init(&reef); + /* init the platform */ err = platform_init(&reef); if (err < 0) diff --git a/src/lib/schedule.c b/src/lib/schedule.c new file mode 100644 index 0000000..5611c8e --- /dev/null +++ b/src/lib/schedule.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2017, 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: Liam Girdwood liam.r.girdwood@linux.intel.com + */ + +#include <stdint.h> +#include <stddef.h> +#include <errno.h> +#include <reef/reef.h> +#include <reef/lock.h> +#include <reef/list.h> +#include <reef/stream.h> +#include <reef/alloc.h> +#include <reef/debug.h> +#include <reef/clock.h> +#include <reef/schedule.h> +#include <platform/timer.h> +#include <platform/clk.h> +#include <reef/audio/component.h> +#include <reef/audio/pipeline.h> +#include <arch/task.h> + +struct schedule_data { + spinlock_t lock; + struct list_item list; /* list of tasks in priority queue */ + uint32_t clock; +}; + +static struct schedule_data *sch; + +/* get time delta */ +static inline uint32_t schedule_time_diff(uint32_t current, uint32_t pipe_time) +{ + uint32_t max = MAX_INT; + + /* does work run in next cycle ? */ + if (pipe_time < current) { + max -= current; + max += pipe_time; + return max; + } else + return pipe_time - current; +} + +/* + * Find the task with the earliest deadline. This may be the running task or a + * queued task. TODO: Reduce cache invalidations by checking if the currently + * running task AND the earliest queued task will both complete before their + * deadlines. If so, then schedule the earlier queued task after the currently + * running task has completed. + */ +static struct task *edf_get_next(void) +{ + struct task *task, *next_task = NULL; + struct list_item *clist; + uint32_t next_delta = MAX_INT, current, delta; + + /* get the current time */ + current = platform_timer_get(NULL); + + /* check every queued or running task in list */ + list_for_item(clist, &sch->list) { + task = container_of(clist, struct task, list); + + /* get earliest deadline */ + delta = schedule_time_diff(current, task->deadline); + if (delta < next_delta) { + next_delta = delta; + next_task = task; + } + } + + return next_task; +} + +/* + * EDF Scheduler - Earliest Deadline First Scheduler. + * + * Schedule task with the earliest deadline from task list. + * Can run in IRQ context. + */ +void schedule_edf(void) +{ + struct task *task; + uint32_t flags; + + tracev_pipe("EDF"); + + /* get next component scheduled */ + spin_lock_irq(&sch->lock, flags); + + /* get next task to be scheduled */ + task = edf_get_next(); + if (task == NULL) + goto out; + + /* is task currently running ? */ + if (task->state == TASK_STATE_RUNNING) + goto out; + + arch_run_task(task); + +out: + spin_unlock_irq(&sch->lock, flags); + + interrupt_clear(PLATFORM_SCHEDULE_IRQ); +} + +/* Add a new task to the scheduler to be run */ +int schedule_task_del(struct task *task) +{ + uint32_t flags; + int ret = 0; + + /* add task to list */ + spin_lock_irq(&sch->lock, flags); + + /* is task already running ? */ + if (task->state == TASK_STATE_RUNNING) { + ret = -EAGAIN; + goto out; + } + + list_item_del(&task->list); + task->state = TASK_STATE_COMPLETED; + +out: + spin_unlock_irq(&sch->lock, flags); + return ret; +} + +/* Add a new task to the scheduler to be run */ +void schedule_task(struct task *task, uint32_t deadline, uint16_t priority, + void *data) +{ + uint32_t flags, time, current, ticks; + + /* get the current time */ + current = platform_timer_get(NULL); + + /* calculate deadline - TODO: include MIPS */ + ticks = clock_us_to_ticks(sch->clock, deadline); + time = current + ticks - PLATFORM_SCHEDULE_COST; + + /* add task to list */ + spin_lock_irq(&sch->lock, flags); + task->deadline = time; + task->priority = priority; + task->sdata = data; + list_item_prepend(&task->list, &sch->list); + task->state = TASK_STATE_QUEUED; + spin_unlock_irq(&sch->lock, flags); +} + +/* Remove a task from the scheduler when complete */ +void schedule_task_complete(struct task *task) +{ + uint32_t flags; + + spin_lock_irq(&sch->lock, flags); + list_item_del(&task->list); + task->state = TASK_STATE_COMPLETED; + spin_unlock_irq(&sch->lock, flags); +} + +void scheduler_run(void *unused) +{ + /* EDF is only scheduler supported atm */ + schedule_edf(); +} + +/* run the scheduler */ +void schedule(void) +{ + /* the scheduler is run in IRQ context */ + interrupt_set(PLATFORM_SCHEDULE_IRQ); +} + +/* Initialise the scheduler */ +int scheduler_init(struct reef *reef) +{ + trace_pipe("ScI"); + + sch = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*sch)); + list_init(&sch->list); + spinlock_init(&sch->lock); + sch->clock = PLATFORM_SCHED_CLOCK; + + /* configure scheduler interrupt */ + interrupt_register(PLATFORM_SCHEDULE_IRQ, scheduler_run, NULL); + interrupt_enable(PLATFORM_SCHEDULE_IRQ); + + return 0; +} diff --git a/src/platform/baytrail/include/platform/platform.h b/src/platform/baytrail/include/platform/platform.h index 3cc19cc..b93641e 100644 --- a/src/platform/baytrail/include/platform/platform.h +++ b/src/platform/baytrail/include/platform/platform.h @@ -50,12 +50,14 @@ struct reef; #define HOST_PAGE_SIZE 4096
/* pipeline IRQ */ +#define PLATFORM_SCHEDULE_IRQ IRQ_NUM_SOFTWARE5 #define PLATFORM_PIPELINE_IRQ IRQ_NUM_SOFTWARE4
#define PLATFORM_IRQ_TASK_HIGH IRQ_NUM_SOFTWARE4 #define PLATFORM_IRQ_TASK_MED IRQ_NUM_SOFTWARE3 #define PLATFORM_IRQ_TASK_LOW IRQ_NUM_SOFTWARE2
+#define PLATFORM_SCHEDULE_COST 200 /* DMA treats PHY addresses as host address unless within DSP region */ #define PLATFORM_HOST_DMA_MASK 0xFF000000
@@ -77,11 +79,13 @@ struct reef; /* Platform Dev DMA buffer config - these should align with DMA engine */ #define PLAT_DAI_PERIOD_FRAMES 48 /* must be multiple of DMA+DEV burst size */ #define PLAT_DAI_PERIODS 2 /* give enough latency for DMA refill */ +#define PLAT_DAI_SCHED 1000 /* scheduling time in usecs */
/* Platform internal buffer config - these should align with DMA engine */ #define PLAT_INT_PERIOD_FRAMES 48 /* must be multiple of DMA+DEV burst size */ #define PLAT_INT_PERIODS 2 /* give enough latency for DMA refill */
+#define PLATFORM_SCHED_CLOCK CLK_SSP
/* DMA channel drain timeout in microseconds */ #define PLATFORM_DMA_TIMEOUT 1333
participants (1)
-
Liam Girdwood