Existing EDMA driver does not take care of multiple EDMA channel controller instances. An upcoming architecture from TI has 2 EDMA channel controller instances. This patch adds support for multiple EDMA CC instances.
These patches have been tested on DM644x. Signed-off-by: Sudhakar Rajashekhara <[email protected]> --- arch/arm/mach-davinci/board-dm355-evm.c | 1 + arch/arm/mach-davinci/board-dm644x-evm.c | 3 +- arch/arm/mach-davinci/dm355.c | 3 +- arch/arm/mach-davinci/dm644x.c | 3 +- arch/arm/mach-davinci/dm646x.c | 3 +- arch/arm/mach-davinci/dma.c | 451 +++++++++++++++++------------ arch/arm/mach-davinci/include/mach/edma.h | 48 ++-- 7 files changed, 295 insertions(+), 217 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index c2cf531..7dbf46f 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -216,6 +216,7 @@ static struct davinci_mmc_config dm355evm_mmc_config = { .max_freq = 50000000, .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED, .version = MMC_CTLR_VERSION_1, + .cc_inst = 0, }; /* Don't connect anything to J10 unless you're only using USB host diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 5aeb085..1a2b045 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -544,7 +544,8 @@ static struct davinci_mmc_config dm6446evm_mmc_config = { .get_cd = dm6444evm_mmc_get_cd, .get_ro = dm6444evm_mmc_get_ro, .wires = 4, - .version = MMC_CTLR_VERSION_1 + .version = MMC_CTLR_VERSION_1, + .cc_inst = 0 }; static struct i2c_board_info __initdata i2c_info[] = { diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 5f31649..6368570 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -479,12 +479,13 @@ static struct edma_soc_info dm355_edma_info = { .n_region = 4, .n_slot = 128, .n_tc = 2, + .n_cc = 1, .noevent = dma_chan_dm355_no_event, }; static struct resource edma_resources[] = { { - .name = "edma_cc", + .name = "edma_cc0", .start = 0x01c00000, .end = 0x01c00000 + SZ_64K - 1, .flags = IORESOURCE_MEM, diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 6a08568..001ce3e 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -402,12 +402,13 @@ static struct edma_soc_info dm644x_edma_info = { .n_region = 4, .n_slot = 128, .n_tc = 2, + .n_cc = 1, .noevent = dma_chan_dm644x_no_event, }; static struct resource edma_resources[] = { { - .name = "edma_cc", + .name = "edma_cc0", .start = 0x01c00000, .end = 0x01c00000 + SZ_64K - 1, .flags = IORESOURCE_MEM, diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index b302f12..0eafc77 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -368,12 +368,13 @@ static struct edma_soc_info dm646x_edma_info = { .n_region = 6, /* 0-1, 4-7 */ .n_slot = 512, .n_tc = 4, + .n_cc = 1, .noevent = dma_chan_dm646x_no_event, }; static struct resource edma_resources[] = { { - .name = "edma_cc", + .name = "edma_cc0", .start = 0x01c00000, .end = 0x01c00000 + SZ_64K - 1, .flags = IORESOURCE_MEM, diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c index 9427c80..f86675e 100644 --- a/arch/arm/mach-davinci/dma.c +++ b/arch/arm/mach-davinci/dma.c @@ -107,101 +107,114 @@ #define EDMA_MAX_DMACH 64 #define EDMA_MAX_PARAMENTRY 512 #define EDMA_MAX_EVQUE 2 /* FIXME too small */ +#define EDMA_MAX_CC 2 /*****************************************************************************/ -static __iomem void *edmacc_regs_base; +static __iomem void *edmacc_regs_base[EDMA_MAX_CC]; -static inline unsigned int edma_read(int offset) +static inline unsigned int edma_read(unsigned cc_inst, int offset) { - return (unsigned int)__raw_readl(edmacc_regs_base + offset); + return (unsigned int)__raw_readl(edmacc_regs_base[cc_inst] + offset); } -static inline void edma_write(int offset, int val) +static inline void edma_write(unsigned cc_inst, int offset, int val) { - __raw_writel(val, edmacc_regs_base + offset); + __raw_writel(val, edmacc_regs_base[cc_inst] + offset); } -static inline void edma_modify(int offset, unsigned and, unsigned or) +static inline void edma_modify(unsigned cc_inst, int offset, unsigned and, + unsigned or) { - unsigned val = edma_read(offset); + unsigned val = edma_read(cc_inst, offset); val &= and; val |= or; - edma_write(offset, val); + edma_write(cc_inst, offset, val); } -static inline void edma_and(int offset, unsigned and) +static inline void edma_and(unsigned cc_inst, int offset, unsigned and) { - unsigned val = edma_read(offset); + unsigned val = edma_read(cc_inst, offset); val &= and; - edma_write(offset, val); + edma_write(cc_inst, offset, val); } -static inline void edma_or(int offset, unsigned or) +static inline void edma_or(unsigned cc_inst, int offset, unsigned or) { - unsigned val = edma_read(offset); + unsigned val = edma_read(cc_inst, offset); val |= or; - edma_write(offset, val); + edma_write(cc_inst, offset, val); } -static inline unsigned int edma_read_array(int offset, int i) +static inline unsigned int edma_read_array(unsigned cc_inst, int offset, int i) { - return edma_read(offset + (i << 2)); + return edma_read(cc_inst, offset + (i << 2)); } -static inline void edma_write_array(int offset, int i, unsigned val) +static inline void edma_write_array(unsigned cc_inst, int offset, int i, + unsigned val) { - edma_write(offset + (i << 2), val); + edma_write(cc_inst, offset + (i << 2), val); } -static inline void edma_modify_array(int offset, int i, +static inline void edma_modify_array(unsigned cc_inst, int offset, int i, unsigned and, unsigned or) { - edma_modify(offset + (i << 2), and, or); + edma_modify(cc_inst, offset + (i << 2), and, or); } -static inline void edma_or_array(int offset, int i, unsigned or) +static inline void edma_or_array(unsigned cc_inst, int offset, int i, + unsigned or) { - edma_or(offset + (i << 2), or); + edma_or(cc_inst, offset + (i << 2), or); } -static inline void edma_or_array2(int offset, int i, int j, unsigned or) +static inline void edma_or_array2(unsigned cc_inst, int offset, int i, int j, + unsigned or) { - edma_or(offset + ((i*2 + j) << 2), or); + edma_or(cc_inst, offset + ((i*2 + j) << 2), or); } -static inline void edma_write_array2(int offset, int i, int j, unsigned val) +static inline void edma_write_array2(unsigned cc_inst, int offset, int i, int j, + unsigned val) { - edma_write(offset + ((i*2 + j) << 2), val); + edma_write(cc_inst, offset + ((i*2 + j) << 2), val); } -static inline unsigned int edma_shadow0_read(int offset) +static inline unsigned int edma_shadow0_read(unsigned cc_inst, int offset) { - return edma_read(EDMA_SHADOW0 + offset); + return edma_read(cc_inst, EDMA_SHADOW0 + offset); } -static inline unsigned int edma_shadow0_read_array(int offset, int i) +static inline unsigned int edma_shadow0_read_array(unsigned cc_inst, int offset, + int i) { - return edma_read(EDMA_SHADOW0 + offset + (i << 2)); + return edma_read(cc_inst, EDMA_SHADOW0 + offset + (i << 2)); } -static inline void edma_shadow0_write(int offset, unsigned val) +static inline void edma_shadow0_write(unsigned cc_inst, int offset, + unsigned val) { - edma_write(EDMA_SHADOW0 + offset, val); + edma_write(cc_inst, EDMA_SHADOW0 + offset, val); } -static inline void edma_shadow0_write_array(int offset, int i, unsigned val) +static inline void edma_shadow0_write_array(unsigned cc_inst, int offset, int i, + unsigned val) { - edma_write(EDMA_SHADOW0 + offset + (i << 2), val); + edma_write(cc_inst, EDMA_SHADOW0 + offset + (i << 2), val); } -static inline unsigned int edma_parm_read(int offset, int param_no) +static inline unsigned int edma_parm_read(unsigned cc_inst, int offset, + int param_no) { - return edma_read(EDMA_PARM + offset + (param_no << 5)); + return edma_read(cc_inst, EDMA_PARM + offset + (param_no << 5)); } -static inline void edma_parm_write(int offset, int param_no, unsigned val) +static inline void edma_parm_write(unsigned cc_inst, int offset, int param_no, + unsigned val) { - edma_write(EDMA_PARM + offset + (param_no << 5), val); + edma_write(cc_inst, EDMA_PARM + offset + (param_no << 5), val); } -static inline void edma_parm_modify(int offset, int param_no, +static inline void edma_parm_modify(unsigned cc_inst, int offset, int param_no, unsigned and, unsigned or) { - edma_modify(EDMA_PARM + offset + (param_no << 5), and, or); + edma_modify(cc_inst, EDMA_PARM + offset + (param_no << 5), and, or); } -static inline void edma_parm_and(int offset, int param_no, unsigned and) +static inline void edma_parm_and(unsigned cc_inst, int offset, int param_no, + unsigned and) { - edma_and(EDMA_PARM + offset + (param_no << 5), and); + edma_and(cc_inst, EDMA_PARM + offset + (param_no << 5), and); } -static inline void edma_parm_or(int offset, int param_no, unsigned or) +static inline void edma_parm_or(unsigned cc_inst, int offset, int param_no, + unsigned or) { - edma_or(EDMA_PARM + offset + (param_no << 5), or); + edma_or(cc_inst, EDMA_PARM + offset + (param_no << 5), or); } /*****************************************************************************/ @@ -209,6 +222,9 @@ static inline void edma_parm_or(int offset, int param_no, unsigned or) /* actual number of DMA channels and slots on this silicon */ static unsigned num_channels; static unsigned num_slots; +static unsigned num_cc; +static unsigned irq_start[EDMA_MAX_CC]; +static unsigned irq_end[EDMA_MAX_CC]; static struct dma_interrupt_data { void (*callback)(unsigned channel, unsigned short ch_status, void *data); @@ -250,7 +266,8 @@ queue_priority_mapping[EDMA_MAX_EVQUE + 1][2] = { /*****************************************************************************/ -static void map_dmach_queue(unsigned ch_no, enum dma_event_q queue_no) +static void map_dmach_queue(unsigned cc_inst, unsigned ch_no, + enum dma_event_q queue_no) { int bit = (ch_no & 0x7) * 4; @@ -259,29 +276,32 @@ static void map_dmach_queue(unsigned ch_no, enum dma_event_q queue_no) queue_no = EVENTQ_1; queue_no &= 7; - edma_modify_array(EDMA_DMAQNUM, (ch_no >> 3), + edma_modify_array(cc_inst, EDMA_DMAQNUM, (ch_no >> 3), ~(0x7 << bit), queue_no << bit); } -static void __init map_queue_tc(int queue_no, int tc_no) +static void __init map_queue_tc(unsigned cc_inst, int queue_no, int tc_no) { int bit = queue_no * 4; - edma_modify(EDMA_QUETCMAP, ~(0x7 << bit), ((tc_no & 0x7) << bit)); + edma_modify(cc_inst, EDMA_QUETCMAP, ~(0x7 << bit), + ((tc_no & 0x7) << bit)); } -static void __init assign_priority_to_queue(int queue_no, int priority) +static void __init assign_priority_to_queue(unsigned cc_inst, int queue_no, + int priority) { int bit = queue_no * 4; - edma_modify(EDMA_QUEPRI, ~(0x7 << bit), ((priority & 0x7) << bit)); + edma_modify(cc_inst, EDMA_QUEPRI, ~(0x7 << bit), + ((priority & 0x7) << bit)); } static inline void -setup_dma_interrupt(unsigned lch, +setup_dma_interrupt(unsigned cc_inst, unsigned lch, void (*callback)(unsigned channel, u16 ch_status, void *data), void *data) { if (!callback) { - edma_shadow0_write_array(SH_IECR, lch >> 5, + edma_shadow0_write_array(cc_inst, SH_IECR, lch >> 5, (1 << (lch & 0x1f))); } @@ -289,13 +309,23 @@ setup_dma_interrupt(unsigned lch, intr_data[lch].data = data; if (callback) { - edma_shadow0_write_array(SH_ICR, lch >> 5, + edma_shadow0_write_array(cc_inst, SH_ICR, lch >> 5, (1 << (lch & 0x1f))); - edma_shadow0_write_array(SH_IESR, lch >> 5, + edma_shadow0_write_array(cc_inst, SH_IESR, lch >> 5, (1 << (lch & 0x1f))); } } +static unsigned int irq2cc(unsigned int irq) +{ + if (irq >= irq_start[0] && irq <= irq_end[0]) + return 0; + else if (irq >= irq_start[1] && irq <= irq_end[1]) + return 1; + else + return 0; +} + /****************************************************************************** * * DMA interrupt handler @@ -304,29 +334,33 @@ setup_dma_interrupt(unsigned lch, static irqreturn_t dma_irq_handler(int irq, void *data) { int i; - unsigned int cnt = 0; + unsigned int cnt = 0, cc_inst; dev_dbg(data, "dma_irq_handler\n"); - if ((edma_shadow0_read_array(SH_IPR, 0) == 0) - && (edma_shadow0_read_array(SH_IPR, 1) == 0)) + cc_inst = irq2cc(irq); + + if ((edma_shadow0_read_array(cc_inst, SH_IPR, 0) == 0) + && (edma_shadow0_read_array(cc_inst, SH_IPR, 1) == 0)) return IRQ_NONE; while (1) { int j; - if (edma_shadow0_read_array(SH_IPR, 0)) + if (edma_shadow0_read_array(cc_inst, SH_IPR, 0)) j = 0; - else if (edma_shadow0_read_array(SH_IPR, 1)) + else if (edma_shadow0_read_array(cc_inst, SH_IPR, 1)) j = 1; else break; dev_dbg(data, "IPR%d %08x\n", j, - edma_shadow0_read_array(SH_IPR, j)); + edma_shadow0_read_array(cc_inst, SH_IPR, j)); for (i = 0; i < 32; i++) { int k = (j << 5) + i; - if (edma_shadow0_read_array(SH_IPR, j) & (1 << i)) { + if (edma_shadow0_read_array(cc_inst, SH_IPR, j) & + (1 << i)) { /* Clear the corresponding IPR bits */ - edma_shadow0_write_array(SH_ICR, j, (1 << i)); + edma_shadow0_write_array(cc_inst, SH_ICR, j, + (1 << i)); if (intr_data[k].callback) { intr_data[k].callback(k, DMA_COMPLETE, intr_data[k].data); @@ -337,7 +371,7 @@ static irqreturn_t dma_irq_handler(int irq, void *data) if (cnt > 10) break; } - edma_shadow0_write(SH_IEVAL, 1); + edma_shadow0_write(cc_inst, SH_IEVAL, 1); return IRQ_HANDLED; } @@ -349,32 +383,38 @@ static irqreturn_t dma_irq_handler(int irq, void *data) static irqreturn_t dma_ccerr_handler(int irq, void *data) { int i; - unsigned int cnt = 0; + unsigned int cnt = 0, cc_inst; dev_dbg(data, "dma_ccerr_handler\n"); - if ((edma_read_array(EDMA_EMR, 0) == 0) && - (edma_read_array(EDMA_EMR, 1) == 0) && - (edma_read(EDMA_QEMR) == 0) && (edma_read(EDMA_CCERR) == 0)) + cc_inst = irq2cc(irq); + + if ((edma_read_array(cc_inst, EDMA_EMR, 0) == 0) && + (edma_read_array(cc_inst, EDMA_EMR, 1) == 0) && + (edma_read(cc_inst, EDMA_QEMR) == 0) && + (edma_read(cc_inst, EDMA_CCERR) == 0)) return IRQ_NONE; while (1) { int j = -1; - if (edma_read_array(EDMA_EMR, 0)) + if (edma_read_array(cc_inst, EDMA_EMR, 0)) j = 0; - else if (edma_read_array(EDMA_EMR, 1)) + else if (edma_read_array(cc_inst, EDMA_EMR, 1)) j = 1; if (j >= 0) { dev_dbg(data, "EMR%d %08x\n", j, - edma_read_array(EDMA_EMR, j)); + edma_read_array(cc_inst, EDMA_EMR, j)); for (i = 0; i < 32; i++) { int k = (j << 5) + i; - if (edma_read_array(EDMA_EMR, j) & (1 << i)) { + if (edma_read_array(cc_inst, EDMA_EMR, j) & + (1 << i)) { /* Clear the corresponding EMR bits */ - edma_write_array(EDMA_EMCR, j, 1 << i); + edma_write_array(cc_inst, EDMA_EMCR, j, + 1 << i); /* Clear any SER */ - edma_shadow0_write_array(SH_SECR, j, - (1 << i)); + edma_shadow0_write_array(cc_inst, + SH_SECR, j, + (1 << i)); if (intr_data[k].callback) { intr_data[k].callback(k, DMA_CC_ERROR, @@ -383,44 +423,46 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data) } } } - } else if (edma_read(EDMA_QEMR)) { + } else if (edma_read(cc_inst, EDMA_QEMR)) { dev_dbg(data, "QEMR %02x\n", - edma_read(EDMA_QEMR)); + edma_read(cc_inst, EDMA_QEMR)); for (i = 0; i < 8; i++) { - if (edma_read(EDMA_QEMR) & (1 << i)) { + if (edma_read(cc_inst, EDMA_QEMR) & (1 << i)) { /* Clear the corresponding IPR bits */ - edma_write(EDMA_QEMCR, 1 << i); - edma_shadow0_write(SH_QSECR, (1 << i)); + edma_write(cc_inst, EDMA_QEMCR, 1 << i); + edma_shadow0_write(cc_inst, SH_QSECR, + (1 << i)); /* NOTE: not reported!! */ } } - } else if (edma_read(EDMA_CCERR)) { + } else if (edma_read(cc_inst, EDMA_CCERR)) { dev_dbg(data, "CCERR %08x\n", - edma_read(EDMA_CCERR)); + edma_read(cc_inst, EDMA_CCERR)); /* FIXME: CCERR.BIT(16) ignored! much better * to just write CCERRCLR with CCERR value... */ for (i = 0; i < 8; i++) { - if (edma_read(EDMA_CCERR) & (1 << i)) { + if (edma_read(cc_inst, EDMA_CCERR) & (1 << i)) { /* Clear the corresponding IPR bits */ - edma_write(EDMA_CCERRCLR, 1 << i); + edma_write(cc_inst, EDMA_CCERRCLR, + 1 << i); /* NOTE: not reported!! */ } } } - if ((edma_read_array(EDMA_EMR, 0) == 0) - && (edma_read_array(EDMA_EMR, 1) == 0) - && (edma_read(EDMA_QEMR) == 0) - && (edma_read(EDMA_CCERR) == 0)) { + if ((edma_read_array(cc_inst, EDMA_EMR, 0) == 0) + && (edma_read_array(cc_inst, EDMA_EMR, 1) == 0) + && (edma_read(cc_inst, EDMA_QEMR) == 0) + && (edma_read(cc_inst, EDMA_CCERR) == 0)) { break; } cnt++; if (cnt > 10) break; } - edma_write(EDMA_EEVAL, 1); + edma_write(cc_inst, EDMA_EEVAL, 1); return IRQ_HANDLED; } @@ -478,7 +520,7 @@ static irqreturn_t dma_tc1err_handler(int irq, void *data) * * Returns the number of the channel, else negative errno. */ -int edma_alloc_channel(int channel, +int edma_alloc_channel(unsigned cc_inst, int channel, void (*callback)(unsigned channel, u16 ch_status, void *data), void *data, enum dma_event_q eventq_no) @@ -500,17 +542,18 @@ int edma_alloc_channel(int channel, } /* ensure access through shadow region 0 */ - edma_or_array2(EDMA_DRAE, 0, channel >> 5, 1 << (channel & 0x1f)); + edma_or_array2(cc_inst, EDMA_DRAE, 0, channel >> 5, + 1 << (channel & 0x1f)); /* ensure no events are pending */ - edma_stop(channel); - memcpy_toio(edmacc_regs_base + PARM_OFFSET(channel), + edma_stop(cc_inst, channel); + memcpy_toio(edmacc_regs_base[cc_inst] + PARM_OFFSET(channel), &dummy_paramset, PARM_SIZE); if (callback) - setup_dma_interrupt(channel, callback, data); + setup_dma_interrupt(cc_inst, channel, callback, data); - map_dmach_queue(channel, eventq_no); + map_dmach_queue(cc_inst, channel, eventq_no); return channel; } @@ -528,15 +571,15 @@ EXPORT_SYMBOL(edma_alloc_channel); * will not be reactivated by linking, chaining, or software calls to * edma_start(). */ -void edma_free_channel(unsigned channel) +void edma_free_channel(unsigned cc_inst, unsigned channel) { if (channel >= num_channels) return; - setup_dma_interrupt(channel, NULL, NULL); + setup_dma_interrupt(cc_inst, channel, NULL, NULL); /* REVISIT should probably take out of shadow region 0 */ - memcpy_toio(edmacc_regs_base + PARM_OFFSET(channel), + memcpy_toio(edmacc_regs_base[cc_inst] + PARM_OFFSET(channel), &dummy_paramset, PARM_SIZE); clear_bit(channel, edma_inuse); } @@ -556,7 +599,7 @@ EXPORT_SYMBOL(edma_free_channel); * * Returns the number of the slot, else negative errno. */ -int edma_alloc_slot(int slot) +int edma_alloc_slot(unsigned cc_inst, int slot) { if (slot < 0) { slot = num_channels; @@ -574,7 +617,7 @@ int edma_alloc_slot(int slot) return -EBUSY; } - memcpy_toio(edmacc_regs_base + PARM_OFFSET(slot), + memcpy_toio(edmacc_regs_base[cc_inst] + PARM_OFFSET(slot), &dummy_paramset, PARM_SIZE); return slot; @@ -589,12 +632,12 @@ EXPORT_SYMBOL(edma_alloc_slot); * Callers are responsible for ensuring the slot is inactive, and will * not be activated. */ -void edma_free_slot(unsigned slot) +void edma_free_slot(unsigned cc_inst, unsigned slot) { if (slot < num_channels || slot >= num_slots) return; - memcpy_toio(edmacc_regs_base + PARM_OFFSET(slot), + memcpy_toio(edmacc_regs_base[cc_inst] + PARM_OFFSET(slot), &dummy_paramset, PARM_SIZE); clear_bit(slot, edma_inuse); } @@ -615,11 +658,11 @@ EXPORT_SYMBOL(edma_free_slot); * Note that the source address is modified during the DMA transfer * according to edma_set_src_index(). */ -void edma_set_src(unsigned slot, dma_addr_t src_port, +void edma_set_src(unsigned cc_inst, unsigned slot, dma_addr_t src_port, enum address_mode mode, enum fifo_width width) { if (slot < num_slots) { - unsigned int i = edma_parm_read(PARM_OPT, slot); + unsigned int i = edma_parm_read(cc_inst, PARM_OPT, slot); if (mode) { /* set SAM and program FWID */ @@ -628,11 +671,11 @@ void edma_set_src(unsigned slot, dma_addr_t src_port, /* clear SAM */ i &= ~SAM; } - edma_parm_write(PARM_OPT, slot, i); + edma_parm_write(cc_inst, PARM_OPT, slot, i); /* set the source port address in source register of param structure */ - edma_parm_write(PARM_SRC, slot, src_port); + edma_parm_write(cc_inst, PARM_SRC, slot, src_port); } } EXPORT_SYMBOL(edma_set_src); @@ -648,11 +691,11 @@ EXPORT_SYMBOL(edma_set_src); * Note that the destination address is modified during the DMA transfer * according to edma_set_dest_index(). */ -void edma_set_dest(unsigned slot, dma_addr_t dest_port, +void edma_set_dest(unsigned cc_inst, unsigned slot, dma_addr_t dest_port, enum address_mode mode, enum fifo_width width) { if (slot < num_slots) { - unsigned int i = edma_parm_read(PARM_OPT, slot); + unsigned int i = edma_parm_read(cc_inst, PARM_OPT, slot); if (mode) { /* set DAM and program FWID */ @@ -661,10 +704,10 @@ void edma_set_dest(unsigned slot, dma_addr_t dest_port, /* clear DAM */ i &= ~DAM; } - edma_parm_write(PARM_OPT, slot, i); + edma_parm_write(cc_inst, PARM_OPT, slot, i); /* set the destination port address in dest register of param structure */ - edma_parm_write(PARM_DST, slot, dest_port); + edma_parm_write(cc_inst, PARM_DST, slot, dest_port); } } EXPORT_SYMBOL(edma_set_dest); @@ -678,11 +721,12 @@ EXPORT_SYMBOL(edma_set_dest); * Returns current source and destination addresses for a particular * parameter RAM slot. Its channel should not be active when this is called. */ -void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst) +void edma_get_position(unsigned cc_inst, unsigned slot, dma_addr_t *src, + dma_addr_t *dst) { struct edmacc_param temp; - edma_read_slot(slot, &temp); + edma_read_slot(cc_inst, slot, &temp); if (src != NULL) *src = temp.src; if (dst != NULL) @@ -700,12 +744,13 @@ EXPORT_SYMBOL(edma_get_position); * memory transfers, or repeated access to a hardware register, as needed. * When accessing hardware registers, both offsets are normally zero. */ -void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx) +void edma_set_src_index(unsigned cc_inst, unsigned slot, s16 src_bidx, + s16 src_cidx) { if (slot < num_slots) { - edma_parm_modify(PARM_SRC_DST_BIDX, slot, + edma_parm_modify(cc_inst, PARM_SRC_DST_BIDX, slot, 0xffff0000, src_bidx); - edma_parm_modify(PARM_SRC_DST_CIDX, slot, + edma_parm_modify(cc_inst, PARM_SRC_DST_CIDX, slot, 0xffff0000, src_cidx); } } @@ -721,12 +766,13 @@ EXPORT_SYMBOL(edma_set_src_index); * memory transfers, or repeated access to a hardware register, as needed. * When accessing hardware registers, both offsets are normally zero. */ -void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx) +void edma_set_dest_index(unsigned cc_inst, unsigned slot, s16 dest_bidx, + s16 dest_cidx) { if (slot < num_slots) { - edma_parm_modify(PARM_SRC_DST_BIDX, slot, + edma_parm_modify(cc_inst, PARM_SRC_DST_BIDX, slot, 0x0000ffff, dest_bidx << 16); - edma_parm_modify(PARM_SRC_DST_CIDX, slot, + edma_parm_modify(cc_inst, PARM_SRC_DST_CIDX, slot, 0x0000ffff, dest_cidx << 16); } } @@ -761,20 +807,21 @@ EXPORT_SYMBOL(edma_set_dest_index); * transfer one frame to (or from) the FIFO. It will probably use * efficient burst modes to access memory. */ -void edma_set_transfer_params(unsigned slot, +void edma_set_transfer_params(unsigned cc_inst, unsigned slot, u16 acnt, u16 bcnt, u16 ccnt, u16 bcnt_rld, enum sync_dimension sync_mode) { if (slot < num_slots) { - edma_parm_modify(PARM_LINK_BCNTRLD, slot, + edma_parm_modify(cc_inst, PARM_LINK_BCNTRLD, slot, 0x0000ffff, bcnt_rld << 16); if (sync_mode == ASYNC) - edma_parm_and(PARM_OPT, slot, ~SYNCDIM); + edma_parm_and(cc_inst, PARM_OPT, slot, ~SYNCDIM); else - edma_parm_or(PARM_OPT, slot, SYNCDIM); + edma_parm_or(cc_inst, PARM_OPT, slot, SYNCDIM); /* Set the acount, bcount, ccount registers */ - edma_parm_write(PARM_A_B_CNT, slot, (bcnt << 16) | acnt); - edma_parm_write(PARM_CCNT, slot, ccnt); + edma_parm_write(cc_inst, PARM_A_B_CNT, slot, + (bcnt << 16) | acnt); + edma_parm_write(cc_inst, PARM_CCNT, slot, ccnt); } } EXPORT_SYMBOL(edma_set_transfer_params); @@ -786,13 +833,14 @@ EXPORT_SYMBOL(edma_set_transfer_params); * * The originating slot should not be part of any active DMA transfer. */ -void edma_link(unsigned from, unsigned to) +void edma_link(unsigned cc_inst, unsigned from, unsigned to) { if (from >= num_slots) return; if (to >= num_slots) return; - edma_parm_modify(PARM_LINK_BCNTRLD, from, 0xffff0000, PARM_OFFSET(to)); + edma_parm_modify(cc_inst, PARM_LINK_BCNTRLD, from, 0xffff0000, + PARM_OFFSET(to)); } EXPORT_SYMBOL(edma_link); @@ -803,11 +851,11 @@ EXPORT_SYMBOL(edma_link); * The originating slot should not be part of any active DMA transfer. * Its link is set to 0xffff. */ -void edma_unlink(unsigned from) +void edma_unlink(unsigned cc_inst, unsigned from) { if (from >= num_slots) return; - edma_parm_or(PARM_LINK_BCNTRLD, from, 0xffff); + edma_parm_or(cc_inst, PARM_LINK_BCNTRLD, from, 0xffff); } EXPORT_SYMBOL(edma_unlink); @@ -825,11 +873,13 @@ EXPORT_SYMBOL(edma_unlink); * calls to set up those parameters in small pieces, and provides * complete control over all transfer options. */ -void edma_write_slot(unsigned slot, const struct edmacc_param *param) +void edma_write_slot(unsigned cc_inst, unsigned slot, + const struct edmacc_param *param) { if (slot >= num_slots) return; - memcpy_toio(edmacc_regs_base + PARM_OFFSET(slot), param, PARM_SIZE); + memcpy_toio(edmacc_regs_base[cc_inst] + PARM_OFFSET(slot), param, + PARM_SIZE); } EXPORT_SYMBOL(edma_write_slot); @@ -841,11 +891,12 @@ EXPORT_SYMBOL(edma_write_slot); * Use this to read data from a parameter RAM slot, perhaps to * save them as a template for later reuse. */ -void edma_read_slot(unsigned slot, struct edmacc_param *param) +void edma_read_slot(unsigned cc_inst, unsigned slot, struct edmacc_param *param) { if (slot >= num_slots) return; - memcpy_fromio(param, edmacc_regs_base + PARM_OFFSET(slot), PARM_SIZE); + memcpy_fromio(param, edmacc_regs_base[cc_inst] + PARM_OFFSET(slot), + PARM_SIZE); } EXPORT_SYMBOL(edma_read_slot); @@ -860,12 +911,12 @@ EXPORT_SYMBOL(edma_read_slot); * This temporarily disables EDMA hardware events on the specified channel, * preventing them from triggering new transfers on its behalf */ -void edma_pause(unsigned channel) +void edma_pause(unsigned cc_inst, unsigned channel) { if (channel < num_channels) { unsigned int mask = (1 << (channel & 0x1f)); - edma_shadow0_write_array(SH_EECR, channel >> 5, mask); + edma_shadow0_write_array(cc_inst, SH_EECR, channel >> 5, mask); } } EXPORT_SYMBOL(edma_pause); @@ -876,12 +927,12 @@ EXPORT_SYMBOL(edma_pause); * * This re-enables EDMA hardware events on the specified channel. */ -void edma_resume(unsigned channel) +void edma_resume(unsigned cc_inst, unsigned channel) { if (channel < num_channels) { unsigned int mask = (1 << (channel & 0x1f)); - edma_shadow0_write_array(SH_EESR, channel >> 5, mask); + edma_shadow0_write_array(cc_inst, SH_EESR, channel >> 5, mask); } } EXPORT_SYMBOL(edma_resume); @@ -897,7 +948,7 @@ EXPORT_SYMBOL(edma_resume); * * Returns zero on success, else negative errno. */ -int edma_start(unsigned channel) +int edma_start(unsigned cc_inst, unsigned channel) { if (channel < num_channels) { int j = channel >> 5; @@ -906,21 +957,21 @@ int edma_start(unsigned channel) /* EDMA channels without event association */ if (test_bit(channel, edma_noevent)) { pr_debug("EDMA: ESR%d %08x\n", j, - edma_shadow0_read_array(SH_ESR, j)); - edma_shadow0_write_array(SH_ESR, j, mask); + edma_shadow0_read_array(cc_inst, SH_ESR, j)); + edma_shadow0_write_array(cc_inst, SH_ESR, j, mask); return 0; } /* EDMA channel with event association */ pr_debug("EDMA: ER%d %08x\n", j, - edma_shadow0_read_array(SH_ER, j)); + edma_shadow0_read_array(cc_inst, SH_ER, j)); /* Clear any pending error */ - edma_write_array(EDMA_EMCR, j, mask); + edma_write_array(cc_inst, EDMA_EMCR, j, mask); /* Clear any SER */ - edma_shadow0_write_array(SH_SECR, j, mask); - edma_shadow0_write_array(SH_EESR, j, mask); + edma_shadow0_write_array(cc_inst, SH_SECR, j, mask); + edma_shadow0_write_array(cc_inst, SH_EESR, j, mask); pr_debug("EDMA: EER%d %08x\n", j, - edma_shadow0_read_array(SH_EER, j)); + edma_shadow0_read_array(cc_inst, SH_EER, j)); return 0; } @@ -937,19 +988,19 @@ EXPORT_SYMBOL(edma_start); * may not be resumed, and the channel's Parameter RAM should be * reinitialized before being reused. */ -void edma_stop(unsigned channel) +void edma_stop(unsigned cc_inst, unsigned channel) { if (channel < num_channels) { int j = channel >> 5; unsigned int mask = (1 << (channel & 0x1f)); - edma_shadow0_write_array(SH_EECR, j, mask); - edma_shadow0_write_array(SH_ECR, j, mask); - edma_shadow0_write_array(SH_SECR, j, mask); - edma_write_array(EDMA_EMCR, j, mask); + edma_shadow0_write_array(cc_inst, SH_EECR, j, mask); + edma_shadow0_write_array(cc_inst, SH_ECR, j, mask); + edma_shadow0_write_array(cc_inst, SH_SECR, j, mask); + edma_write_array(cc_inst, EDMA_EMCR, j, mask); pr_debug("EDMA: EER%d %08x\n", j, - edma_shadow0_read_array(SH_EER, j)); + edma_shadow0_read_array(cc_inst, SH_EER, j)); /* REVISIT: consider guarding against inappropriate event * chaining by overwriting with dummy_paramset. @@ -971,20 +1022,20 @@ EXPORT_SYMBOL(edma_stop); * *****************************************************************************/ -void edma_clean_channel(unsigned channel) +void edma_clean_channel(unsigned cc_inst, unsigned channel) { if (channel < num_channels) { int j = (channel >> 5); unsigned int mask = 1 << (channel & 0x1f); pr_debug("EDMA: EMR%d %08x\n", j, - edma_read_array(EDMA_EMR, j)); - edma_shadow0_write_array(SH_ECR, j, mask); + edma_read_array(cc_inst, EDMA_EMR, j)); + edma_shadow0_write_array(cc_inst, SH_ECR, j, mask); /* Clear the corresponding EMR bits */ - edma_write_array(EDMA_EMCR, j, mask); + edma_write_array(cc_inst, EDMA_EMCR, j, mask); /* Clear any SER */ - edma_shadow0_write_array(SH_SECR, j, mask); - edma_write(EDMA_CCERRCLR, (1 << 16) | 0x3); + edma_shadow0_write_array(cc_inst, SH_SECR, j, mask); + edma_write(cc_inst, EDMA_CCERRCLR, (1 << 16) | 0x3); } } EXPORT_SYMBOL(edma_clean_channel); @@ -992,16 +1043,17 @@ EXPORT_SYMBOL(edma_clean_channel); /* * edma_clear_event - clear an outstanding event on the DMA channel * Arguments: + * cc_inst - EDMA instance * channel - channel number */ -void edma_clear_event(unsigned channel) +void edma_clear_event(unsigned cc_inst, unsigned channel) { if (channel >= num_channels) return; if (channel < 32) - edma_write(EDMA_ECR, 1 << channel); + edma_write(cc_inst, EDMA_ECR, 1 << channel); else - edma_write(EDMA_ECRH, 1 << (channel - 32)); + edma_write(cc_inst, EDMA_ECRH, 1 << (channel - 32)); } EXPORT_SYMBOL(edma_clear_event); @@ -1010,40 +1062,45 @@ EXPORT_SYMBOL(edma_clear_event); static int __init edma_probe(struct platform_device *pdev) { struct edma_soc_info *info = pdev->dev.platform_data; - int i; + int i, j; int status; const s8 *noevent; int irq = 0, err_irq = 0; - struct resource *r; - resource_size_t len; + struct resource *r = NULL; + resource_size_t len = 0; + char name[10]; if (!info) return -ENODEV; - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "edma_cc"); - if (!r) - return -ENODEV; + num_cc = min_t(unsigned, info->n_cc, EDMA_MAX_CC); - len = r->end - r->start + 1; + for (i = 0; i < num_cc; i++) { + sprintf(name, "edma_cc%d", i); + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + if (!r) + return -ENODEV; - r = request_mem_region(r->start, len, r->name); - if (!r) - return -EBUSY; + len = r->end - r->start + 1; - edmacc_regs_base = ioremap(r->start, len); - if (!edmacc_regs_base) { - status = -EBUSY; - goto fail1; + r = request_mem_region(r->start, len, r->name); + if (!r) + return -EBUSY; + + edmacc_regs_base[i] = ioremap(r->start, len); + if (!edmacc_regs_base[i]) { + status = -EBUSY; + goto fail1; + } } num_channels = min_t(unsigned, info->n_channel, EDMA_MAX_DMACH); num_slots = min_t(unsigned, info->n_slot, EDMA_MAX_PARAMENTRY); - dev_dbg(&pdev->dev, "DMA REG BASE ADDR=%p\n", edmacc_regs_base); - - for (i = 0; i < num_slots; i++) - memcpy_toio(edmacc_regs_base + PARM_OFFSET(i), - &dummy_paramset, PARM_SIZE); + for (j = 0; j < num_cc; j++) + for (i = 0; i < num_slots; i++) + memcpy_toio(edmacc_regs_base[j] + PARM_OFFSET(i), + &dummy_paramset, PARM_SIZE); noevent = info->noevent; if (noevent) { @@ -1052,7 +1109,8 @@ static int __init edma_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - status = request_irq(irq, dma_irq_handler, 0, "edma", &pdev->dev); + irq_start[0] = irq; + status = request_irq(irq, dma_irq_handler, 0, "edma0", &pdev->dev); if (status < 0) { dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n", irq, status); @@ -1060,8 +1118,9 @@ static int __init edma_probe(struct platform_device *pdev) } err_irq = platform_get_irq(pdev, 1); + irq_end[0] = err_irq; status = request_irq(err_irq, dma_ccerr_handler, 0, - "edma_error", &pdev->dev); + "edma0_error", &pdev->dev); if (status < 0) { dev_dbg(&pdev->dev, "request_irq %d failed --> %d\n", err_irq, status); @@ -1089,22 +1148,29 @@ static int __init edma_probe(struct platform_device *pdev) * This way, long transfers on the low priority queue * started by the codec engine will not cause audio defects. */ - for (i = 0; i < num_channels; i++) - map_dmach_queue(i, EVENTQ_1); + for (j = 0; j < num_cc; j++) + for (i = 0; i < num_channels; i++) + map_dmach_queue(j, i, EVENTQ_1); /* Event queue to TC mapping */ - for (i = 0; queue_tc_mapping[i][0] != -1; i++) - map_queue_tc(queue_tc_mapping[i][0], queue_tc_mapping[i][1]); + for (j = 0; j < num_cc; j++) + for (i = 0; queue_tc_mapping[i][0] != -1; i++) + map_queue_tc(j, queue_tc_mapping[i][0], + queue_tc_mapping[i][1]); /* Event queue priority mapping */ - for (i = 0; queue_priority_mapping[i][0] != -1; i++) - assign_priority_to_queue(queue_priority_mapping[i][0], - queue_priority_mapping[i][1]); - - for (i = 0; i < info->n_region; i++) { - edma_write_array2(EDMA_DRAE, i, 0, 0x0); - edma_write_array2(EDMA_DRAE, i, 1, 0x0); - edma_write_array(EDMA_QRAE, i, 0x0); + for (j = 0; j < num_cc; j++) + for (i = 0; queue_priority_mapping[i][0] != -1; i++) + assign_priority_to_queue(j, + queue_priority_mapping[i][0], + queue_priority_mapping[i][1]); + + for (j = 0; j < num_cc; j++) { + for (i = 0; i < info->n_region; i++) { + edma_write_array2(j, EDMA_DRAE, i, 0, 0x0); + edma_write_array2(j, EDMA_DRAE, i, 1, 0x0); + edma_write_array(j, EDMA_QRAE, i, 0x0); + } } return 0; @@ -1114,7 +1180,8 @@ fail: free_irq(err_irq, NULL); if (irq) free_irq(irq, NULL); - iounmap(edmacc_regs_base); + for (i = 0; i < num_cc; i++) + iounmap(edmacc_regs_base[i]); fail1: release_mem_region(r->start, len); return status; diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h index b467358..e208a59 100644 --- a/arch/arm/mach-davinci/include/mach/edma.h +++ b/arch/arm/mach-davinci/include/mach/edma.h @@ -175,39 +175,44 @@ enum sync_dimension { #define EDMA_SLOT_ANY -1 /* for edma_alloc_slot() */ /* alloc/free DMA channels and their dedicated parameter RAM slots */ -int edma_alloc_channel(int channel, +int edma_alloc_channel(unsigned cc_inst, int channel, void (*callback)(unsigned channel, u16 ch_status, void *data), void *data, enum dma_event_q); -void edma_free_channel(unsigned channel); +void edma_free_channel(unsigned cc_inst, unsigned channel); /* alloc/free parameter RAM slots */ -int edma_alloc_slot(int slot); -void edma_free_slot(unsigned slot); +int edma_alloc_slot(unsigned cc_inst, int slot); +void edma_free_slot(unsigned cc_inst, unsigned slot); /* calls that operate on part of a parameter RAM slot */ -void edma_set_src(unsigned slot, dma_addr_t src_port, +void edma_set_src(unsigned cc_inst, unsigned slot, dma_addr_t src_port, enum address_mode mode, enum fifo_width); -void edma_set_dest(unsigned slot, dma_addr_t dest_port, +void edma_set_dest(unsigned cc_inst, unsigned slot, dma_addr_t dest_port, enum address_mode mode, enum fifo_width); -void edma_get_position(unsigned slot, dma_addr_t *src, dma_addr_t *dst); -void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx); -void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx); -void edma_set_transfer_params(unsigned slot, u16 acnt, u16 bcnt, u16 ccnt, - u16 bcnt_rld, enum sync_dimension sync_mode); -void edma_link(unsigned from, unsigned to); -void edma_unlink(unsigned from); +void edma_get_position(unsigned cc_inst, unsigned slot, dma_addr_t *src, + dma_addr_t *dst); +void edma_set_src_index(unsigned cc_inst, unsigned slot, s16 src_bidx, + s16 src_cidx); +void edma_set_dest_index(unsigned cc_inst, unsigned slot, s16 dest_bidx, + s16 dest_cidx); +void edma_set_transfer_params(unsigned cc_inst, unsigned slot, u16 acnt, + u16 bcnt, u16 ccnt, u16 bcnt_rld, enum sync_dimension sync_mode); +void edma_link(unsigned cc_inst, unsigned from, unsigned to); +void edma_unlink(unsigned cc_inst, unsigned from); /* calls that operate on an entire parameter RAM slot */ -void edma_write_slot(unsigned slot, const struct edmacc_param *params); -void edma_read_slot(unsigned slot, struct edmacc_param *params); +void edma_write_slot(unsigned cc_inst, unsigned slot, + const struct edmacc_param *params); +void edma_read_slot(unsigned cc_inst, unsigned slot, + struct edmacc_param *params); /* channel control operations */ -int edma_start(unsigned channel); -void edma_stop(unsigned channel); -void edma_clean_channel(unsigned channel); -void edma_clear_event(unsigned channel); -void edma_pause(unsigned channel); -void edma_resume(unsigned channel); +int edma_start(unsigned cc_inst, unsigned channel); +void edma_stop(unsigned cc_inst, unsigned channel); +void edma_clean_channel(unsigned cc_inst, unsigned channel); +void edma_clear_event(unsigned cc_inst, unsigned channel); +void edma_pause(unsigned cc_inst, unsigned channel); +void edma_resume(unsigned cc_inst, unsigned channel); /* UNRELATED TO DMA */ int davinci_alloc_iram(unsigned size); @@ -221,6 +226,7 @@ struct edma_soc_info { unsigned n_region; unsigned n_slot; unsigned n_tc; + unsigned n_cc; /* list of channels with no even trigger; terminated by "-1" */ const s8 *noevent; -- 1.5.6 _______________________________________________ Davinci-linux-open-source mailing list [email protected] http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
