Signed-off-by: Vladimir Barinov Index: linux-2.6.25-rc1/arch/arm/mach-davinci/dma.c =================================================================== --- /dev/null +++ linux-2.6.25-rc1/arch/arm/mach-davinci/dma.c @@ -0,0 +1,919 @@ +/* + + * TI DaVinci DMA Support + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (c) 2007, MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define DAVINCI_EDMA_DEBUG 0 +#if DAVINCI_EDMA_DEBUG +#define DBG(x...) printk(KERN_DEBUG x) +#else +#define DBG(x...) +#endif + +static struct davinci_dma_lch { + int dev_id; + int in_use; + int param_no; + int tcc; +} dma_chan[EDMA_NUM_PARAMENTRY]; + +static struct davinci_dma_lch_intr { + void (*callback) (int lch, u16 ch_status, void *data); + void *data; +} intr_data[EDMA_NUM_DMACH]; + +#define dma_handle_cb(lch, status) do { \ + if (intr_data[lch].callback) \ + intr_data[lch].callback(lch, status, intr_data[lch].data); \ +} while (0) + +/* + * Each bit field of the elements bellow indicate the corresponding + * (EDMA + QDMA) channel availability on arm side events + */ +static unsigned int dma2arm_map[3] = { + 0xffffffff, 0xffffffff, 0x0 +}; + +/* + * Each bit field of the elements bellow indicate corresponding PARAM entry + * availibility on arm side events + */ +static unsigned int param2arm_map[] = { + 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, +}; + +static int evtqueue_tc_map[EDMA_NUM_EVQUE][2] = { + /* {event queue no, TC no} */ + {0, 0}, + {1, 1}, +}; + +static int evtqueue_priority_map[EDMA_NUM_EVQUE][2] = { + /* {event queue no, Priority} */ + {0, 0}, + {1, 1}, +}; + +static unsigned int qdma2param_map[8]; +static unsigned int edma2event_map[EDMA_NUM_DMACH / 32]; +static unsigned int dma_intr_reseved[EDMA_NUM_DMACH / 32]; +static unsigned int param_entry_reserved[EDMA_NUM_PARAMENTRY / 32]; + +static void map_edmach2evt_queue(int lch, int eventq) +{ + u32 reg = EDMA_DMAQNUM(lch >> 3); + int bit = (lch % 8) << 2; + + CLEAR_REG_VAL(0x7 << bit, reg); + SET_REG_VAL((eventq & 0x7) << bit, reg); +} + +static void map_qdmach2evt_queue(int lch, int eventq) +{ + u32 reg = EDMA_QDMAQNUM; + int bit = (lch - EDMA_NUM_DMACH) << 2; + + CLEAR_REG_VAL(0x7 << bit, reg); + SET_REG_VAL((eventq & 0x7) << bit, reg); +} + +static void map_qdmach2param(int lch, int param_no) +{ + u32 reg; + + reg = EDMA_QCHMAP(lch - EDMA_NUM_DMACH); + CLEAR_REG_VAL(PAENTRY | TRWORD, reg); + SET_REG_VAL(((param_no & 0x1ff) << 5) | (QDMA_TRWORD << 2), reg); +} + +static int reserve_param(int lch) +{ + int i; + + /* The EDMA Channels are mapped to the first PARAM entries */ + if (dma_is_edmach(lch)) { + param_reserve(lch); + return lch; + } + + for (i = EDMA_NUM_DMACH; i < EDMA_NUM_PARAMENTRY; i++) { + if (param_is_free(i) && param_is_valid(i)) { + param_reserve(i); + return i; + } + } + + /* there is no free PaRam */ + return -EBUSY; +} + +static void free_param(int param_no) +{ + param_free(param_no); +} + +static int reserve_dma_interrupt(int lch, int tcc) +{ + if (dma_is_edmach(lch)) { + if (interrupt_is_free(lch)) { + interrupt_reserve(lch); + return lch; + } + } else if (dma_is_qdmach(lch)) { + int i = 0; + + if (tcc != TCC_ANY) { + if (!interrupt_is_free(tcc)) + return -EBUSY; + if (edmach_has_event(tcc)) + return -EINVAL; + interrupt_reserve(tcc); + return tcc; + } + + while (i < EDMA_NUM_DMACH) { + if (interrupt_is_free(i) && !edmach_has_event(i)) { + interrupt_reserve(i); + return i; + } + i++; + } + } + + /* there is no free interrupt channels */ + return -EBUSY; +} + +static void free_dma_interrupt(int ch_irq) +{ + interrupt_free(ch_irq); +} + +static int request_dma_interrupt(void (*callback) (int lch, u16 ch_status, + void *data), + void *data, int *lch, int *tcc) +{ + int ch_irq; + u32 reg, mask; + + if (callback) { + ch_irq = reserve_dma_interrupt(*lch, *tcc); + if (ch_irq < 0) + return ch_irq; + + reg = ch_irq < 32 ? EDMA_SH_IESR(0) : EDMA_SH_IESRH(0); + mask = 1 << (ch_irq < 32 ? ch_irq : ch_irq - 32); + SET_REG_VAL(mask, reg); + + dma_chan[*lch].tcc = ch_irq; + *tcc = ch_irq; + intr_data[*tcc].callback = callback; + intr_data[*tcc].data = data; + } else { + dma_chan[*lch].tcc = -1; + } + + return 0; +} + +/** + * DMA transfer completion interrupt handler + */ +static irqreturn_t davinci_dma_irq_handler(int irq, void *dev_id) +{ + if (!(dma_read(EDMA_SH_IPR(0)) || dma_read(EDMA_SH_IPRH(0)))) + return IRQ_NONE; + + while (1) { + u32 status_l = dma_read(EDMA_SH_IPR(0)); + u32 status_h = dma_read(EDMA_SH_IPRH(0)); + int lch; + int i; + + if (!(status_l || status_h)) + break; + + lch = 0; + while (status_l) { + i = ffs(status_l); + lch += i; + /* Clear the corresponding IPR bits */ + SET_REG_VAL(1 << (lch - 1), EDMA_SH_ICR(0)); + dma_handle_cb(lch - 1, DMA_COMPLETE); + status_l >>= i; + } + + lch = 32; + while (status_h) { + i = ffs(status_h); + lch += i; + /* Clear the corresponding IPR bits */ + SET_REG_VAL(1 << (lch - 33), EDMA_SH_ICRH(0)); + dma_handle_cb(lch - 1, DMA_COMPLETE); + status_h >>= i; + } + } + dma_write(0x1, EDMA_SH_IEVAL(0)); + + return IRQ_HANDLED; +} + +/** + * DMA error interrupt handler + */ +static irqreturn_t davinci_dma_ccerr_handler(int irq, void *dev_id) +{ + if (!(dma_read(EDMA_EMR) || dma_read(EDMA_EMRH) || + dma_read(EDMA_QEMR) || dma_read(EDMA_CCERR))) + return IRQ_NONE; + + while (1) { + u32 status_emr = dma_read(EDMA_EMR); + u32 status_emrh = dma_read(EDMA_EMRH); + u32 status_qemr = dma_read(EDMA_QEMR); + u32 status_ccerr = dma_read(EDMA_CCERR); + int lch; + int i; + + if (!(status_emr || status_emrh || status_qemr || status_ccerr)) + break; + + lch = 0; + while (status_emr) { + i = ffs(status_emr); + lch += i; + /* Clear the corresponding EMR bits */ + SET_REG_VAL(1 << (lch - 1), EDMA_EMCR); + /* Clear any SER */ + SET_REG_VAL(1 << (lch - 1), EDMA_SH_SECR(0)); + dma_handle_cb(lch - 1, DMA_CC_ERROR); + status_emr >>= i; + } + + lch = 32; + while (status_emrh) { + i = ffs(status_emrh); + lch += i; + /* Clear the corresponding IPR bits */ + SET_REG_VAL(1 << (lch - 1), EDMA_EMCRH); + /* Clear any SER */ + SET_REG_VAL(1 << (lch - 1), EDMA_SH_SECRH(0)); + dma_handle_cb(lch - 1, DMA_CC_ERROR); + status_emrh >>= i; + } + + lch = 0; + while (status_qemr) { + i = ffs(status_qemr); + lch += i; + /* Clear the corresponding IPR bits */ + SET_REG_VAL(1 << (lch - 1), EDMA_QEMCR); + SET_REG_VAL(1 << (lch - 1), EDMA_SH_QSECR(0)); + status_qemr >>= i; + } + + lch = 0; + while (status_ccerr) { + i = ffs(status_ccerr); + lch += i; + /* Clear the corresponding IPR bits */ + SET_REG_VAL(1 << (lch - 1), EDMA_CCERRCLR); + status_ccerr >>= i; + } + } + dma_write(0x1, EDMA_EEVAL); + + return IRQ_HANDLED; +} + +/** + * DMA channel request - request for the Davinci DMA channel + * + * dev_id - DMA channel number + * + * EX: DAVINCI_DMA_MCBSP_TX - For requesting a DMA MasterChannel with MCBSP_TX + * event association + * + * EDMA_DMA_CHANNEL_ANY - For requesting a DMA Master channel which does + * not has event association + * + * DAVINCI_EDMA_PARAM_ANY - for requesting a DMA Slave Channel + * + * dev_name - name of the dma channel in human readable format + * callback - channel callback function (valied only if you are requesting + * for a DMA MasterChannel) + * data - private data for the channel to be requested + * lch - contains the device id allocated + * tcc - specifies the channel number on which the interrupt is generated + * Valid for QDMA and PARAM channes + * eventq_no - Event Queue no to which the channel will be associated with + * (valied only if you are requesting for a DMA MasterChannel) + * Values : EVENTQ_0/EVENTQ_1 for event queue 0/1. + * + * Return: zero on success or error on failure + */ +int davinci_request_dma(int dev_id, const char *dev_name, + void (*callback) (int lch, u16 ch_status, void *data), + void *data, int *lch, int *tcc, + enum dma_event_q eventq_no) +{ + int ret_val = 0; + int temp_ch = 0; + int i; + u32 reg, mask; + + if (dma_is_edmach(dev_id)) { + *lch = dev_id; + temp_ch = *lch; + + if (!dmach_is_valid(dev_id)) + return -EINVAL; + + if (dma_chan[dev_id].in_use) + return -EBUSY; + + dma_chan[*lch].param_no = reserve_param(*lch); + if (dma_chan[*lch].param_no == -1) + return -EBUSY; + + reg = dev_id < 32 ? EDMA_DRAE(0) : EDMA_DRAEH(0); + mask = 1 << (dev_id < 32 ? dev_id : dev_id - 32); + SET_REG_VAL(mask, reg); + + ret_val = request_dma_interrupt(callback, data, lch, tcc); + if (ret_val) + return ret_val; + + /* Map EDMA channel to event queue */ + map_edmach2evt_queue(dev_id, eventq_no); + } else if (dma_is_qdmach(dev_id)) { + *lch = dev_id; + + if (!dmach_is_valid(dev_id)) + return -EINVAL; + + dma_chan[*lch].param_no = reserve_param(*lch); + if (dma_chan[*lch].param_no == -1) + return -EBUSY; + + temp_ch = dev_id - EDMA_NUM_DMACH; + qdma2param_map[temp_ch] = dma_chan[*lch].param_no; + temp_ch = qdma2param_map[temp_ch]; + + if (dma_chan[temp_ch].in_use) + return -EBUSY; + + SET_REG_VAL(1 << (dev_id - EDMA_NUM_DMACH), EDMA_QRAE(0)); + + ret_val = request_dma_interrupt(callback, data, lch, tcc); + if (ret_val) + return ret_val; + + /* Map QDMA channel to event queue */ + map_qdmach2evt_queue(*lch, eventq_no); + /* Map QDMA channel to PaRAM Set */ + map_qdmach2param(*lch, dma_chan[*lch].param_no); + + dma_chan[temp_ch].tcc = dma_chan[*lch].tcc; + dma_chan[temp_ch].param_no = dma_chan[*lch].param_no; + } else if (dev_id == PARAM_ANY) { + for (i = (EDMA_NUM_DMACH + EDMA_NUM_QDMACH); + i < EDMA_NUM_PARAMENTRY; i++) { + if (!dma_chan[i].in_use) { + *lch = i; + temp_ch = *lch; + + dma_chan[*lch].param_no = reserve_param(*lch); + if (dma_chan[*lch].param_no == -1) + return -EBUSY; + + dma_chan[*lch].tcc = *tcc; + break; + } + } + } + + dma_chan[temp_ch].in_use = 1; + dma_chan[temp_ch].dev_id = *lch; + + reg = EDMA_PARAM_OPT(dma_chan[temp_ch].param_no); + if (dma_chan[*lch].tcc != TCC_ANY) { + CLEAR_REG_VAL(TCC, reg); + SET_REG_VAL((0x3f & dma_chan[*lch].tcc) << 12, reg); + /* set TCINTEN bit in PARAM entry */ + SET_REG_VAL(TCINTEN, reg); + } else { + CLEAR_REG_VAL(TCINTEN, reg); + } + /* assign the link field to no link. i.e 0xffff */ + SET_REG_VAL(0xffff, + EDMA_PARAM_LINK_BCNTRLD(dma_chan[temp_ch].param_no)); + + return 0; +} +EXPORT_SYMBOL(davinci_request_dma); + +void davinci_free_dma(int lch) +{ + u32 reg, mask; + int tcc; + + if (dma_is_qdmach(lch)) + lch = qdma2param_map[lch - EDMA_NUM_DMACH]; + + free_param(dma_chan[lch].param_no); + + if (lch >= 0 && lch < (EDMA_NUM_DMACH + EDMA_NUM_QDMACH)) { + tcc = dma_chan[lch].tcc; + free_dma_interrupt(tcc); + + if (lch < EDMA_NUM_DMACH) { + /* Clear the corresponding IPR bits */ + reg = tcc < 32 ? EDMA_SH_ICR(0) : EDMA_SH_ICRH(0); + mask = 1 << (tcc < 32 ? tcc : tcc - 32); + SET_REG_VAL(mask, reg); + } + + intr_data[tcc].callback = NULL; + intr_data[tcc].data = NULL; + } + + dma_chan[lch].in_use = 0; +} +EXPORT_SYMBOL(davinci_free_dma); + +/** + * DMA source parameters setup + * Arguments: + * lch - logical channel number + * src_port - Source port address + * mode - indicates wether addressing mode is fifo. + */ +void davinci_set_dma_src_params(int lch, u32 src_port, + enum address_mode mode, enum fifo_width width) +{ + u32 reg; + + if (dma_is_qdmach(lch)) + lch = qdma2param_map[lch - EDMA_NUM_DMACH]; + + if (!(lch >= 0 && lch < EDMA_NUM_PARAMENTRY)) + return; + + dma_write(src_port, EDMA_PARAM_SRC(dma_chan[lch].param_no)); + /* set the fifo addressing mode */ + if (mode) { + reg = EDMA_PARAM_OPT(dma_chan[lch].param_no); + /* reset SAM and FWID */ + CLEAR_REG_VAL(SAM | EDMA_FWID, reg); + /* set SAM and program FWID */ + SET_REG_VAL(mode | ((width & 0x7) << 8), reg); + } +} +EXPORT_SYMBOL(davinci_set_dma_src_params); + +/** + * DMA destination parameters setup + * Arguments: + * lch - logical channel number or param device + * dest_port - destination port address + * mode - indicates wether addressing mode is fifo. + */ +void davinci_set_dma_dest_params(int lch, u32 dest_port, + enum address_mode mode, enum fifo_width width) +{ + u32 reg; + + if (dma_is_qdmach(lch)) + lch = qdma2param_map[lch - EDMA_NUM_DMACH]; + + if (!(lch >= 0 && lch < EDMA_NUM_PARAMENTRY)) + return; + + dma_write(dest_port, EDMA_PARAM_DST(dma_chan[lch].param_no)); + /* set the fifo addressing mode */ + if (mode) { + reg = EDMA_PARAM_OPT(dma_chan[lch].param_no); + /* reset DAM and FWID */ + CLEAR_REG_VAL(DAM | EDMA_FWID, reg); + /* set DAM and program FWID */ + SET_REG_VAL((mode << 1) | ((width & 0x7) << 8), reg); + } +} +EXPORT_SYMBOL(davinci_set_dma_dest_params); + +/** + * DMA source index setup + * Arguments: + * lch - logical channel number or param device + * srcbidx - source B-register index + * srccidx - source C-register index + */ +void davinci_set_dma_src_index(int lch, u16 src_bidx, u16 src_cidx) +{ + u32 reg; + + if (dma_is_qdmach(lch)) + lch = qdma2param_map[lch - EDMA_NUM_DMACH]; + + if (!(lch >= 0 && lch < EDMA_NUM_PARAMENTRY)) + return; + + reg = EDMA_PARAM_SRC_DST_BIDX(dma_chan[lch].param_no); + CLEAR_REG_VAL(0xffff, reg); + SET_REG_VAL(src_bidx, reg); + + reg = EDMA_PARAM_SRC_DST_CIDX(dma_chan[lch].param_no); + CLEAR_REG_VAL(0xffff, reg); + SET_REG_VAL(src_cidx, reg); +} +EXPORT_SYMBOL(davinci_set_dma_src_index); + +/** + * DMA destination index setup + * Arguments: + * lch - logical channel number or param device + * srcbidx - dest B-register index + * srccidx - dest C-register index + */ +void davinci_set_dma_dest_index(int lch, u16 dest_bidx, u16 dest_cidx) +{ + u32 reg; + + if (dma_is_qdmach(lch)) + lch = qdma2param_map[lch - EDMA_NUM_DMACH]; + + if (!(lch >= 0 && lch < EDMA_NUM_PARAMENTRY)) + return; + + reg = EDMA_PARAM_SRC_DST_BIDX(dma_chan[lch].param_no); + CLEAR_REG_VAL(0xffff0000, reg); + SET_REG_VAL((u32)dest_bidx << 16, reg); + + reg = EDMA_PARAM_SRC_DST_CIDX(dma_chan[lch].param_no); + CLEAR_REG_VAL(0xffff0000, reg); + SET_REG_VAL((u32)dest_cidx << 16, reg); +} +EXPORT_SYMBOL(davinci_set_dma_dest_index); + +/** + * DMA transfer parameters setup + * Arguments: + * lch - logical channel number or param device + * acnt - acnt register value to be configured + * bcnt - bcnt register value to be configured + * ccnt - ccnt register value to be configured + */ +void davinci_set_dma_transfer_params(int lch, u16 acnt, u16 bcnt, u16 ccnt, + u16 bcntrld, enum sync_dimension sync_mode) +{ + u32 reg; + + if (dma_is_qdmach(lch)) + lch = qdma2param_map[lch - EDMA_NUM_DMACH]; + + if (!(lch >= 0 && lch < EDMA_NUM_PARAMENTRY)) + return; + + reg = EDMA_PARAM_LINK_BCNTRLD(dma_chan[lch].param_no); + CLEAR_REG_VAL(0xffff0000, reg); + SET_REG_VAL((u32)bcntrld << 16, reg); + + reg = EDMA_PARAM_OPT(dma_chan[lch].param_no); + if (sync_mode == ASYNC) + CLEAR_REG_VAL(SYNCDIM, reg); + else + SET_REG_VAL(SYNCDIM, reg); + + /* Set the acount, bcount, ccount registers */ + dma_write(((u32)bcnt << 16) | acnt, + EDMA_PARAM_A_B_CNT(dma_chan[lch].param_no)); + dma_write(ccnt, EDMA_PARAM_CCNT(dma_chan[lch].param_no)); +} +EXPORT_SYMBOL(davinci_set_dma_transfer_params); + +void davinci_set_dma_params(int lch, struct paramentry_descriptor *d) +{ + if (dma_is_qdmach(lch)) + lch = qdma2param_map[lch - EDMA_NUM_DMACH]; + + if (!(lch >= 0 && lch < EDMA_NUM_PARAMENTRY)) + return; + + dma_write(d->opt, EDMA_PARAM_OPT(dma_chan[lch].param_no)); + dma_write(d->src, EDMA_PARAM_SRC(dma_chan[lch].param_no)); + dma_write(d->a_b_cnt, EDMA_PARAM_A_B_CNT(dma_chan[lch].param_no)); + dma_write(d->dst, EDMA_PARAM_DST(dma_chan[lch].param_no)); + dma_write(d->src_dst_bidx, + EDMA_PARAM_SRC_DST_BIDX(dma_chan[lch].param_no)); + dma_write(d->link_bcntrld, + EDMA_PARAM_LINK_BCNTRLD(dma_chan[lch].param_no)); + dma_write(d->src_dst_cidx, + EDMA_PARAM_SRC_DST_CIDX(dma_chan[lch].param_no)); + dma_write(d->ccnt, EDMA_PARAM_CCNT(dma_chan[lch].param_no)); +} +EXPORT_SYMBOL(davinci_set_dma_params); + +void davinci_get_dma_params(int lch, struct paramentry_descriptor *d) +{ + if (dma_is_qdmach(lch)) + lch = qdma2param_map[lch - EDMA_NUM_DMACH]; + + if (!(lch >= 0 && lch < EDMA_NUM_PARAMENTRY)) + return; + + d->opt = dma_read(EDMA_PARAM_OPT(dma_chan[lch].param_no)); + d->src = dma_read(EDMA_PARAM_SRC(dma_chan[lch].param_no)); + d->a_b_cnt = dma_read(EDMA_PARAM_A_B_CNT(dma_chan[lch].param_no)); + d->dst = dma_read(EDMA_PARAM_DST(dma_chan[lch].param_no)); + d->src_dst_bidx = + dma_read(EDMA_PARAM_SRC_DST_BIDX(dma_chan[lch].param_no)); + d->link_bcntrld = + dma_read(EDMA_PARAM_LINK_BCNTRLD(dma_chan[lch].param_no)); + d->src_dst_cidx = + dma_read(EDMA_PARAM_SRC_DST_CIDX(dma_chan[lch].param_no)); + d->ccnt = dma_read(EDMA_PARAM_CCNT(dma_chan[lch].param_no)); +} +EXPORT_SYMBOL(davinci_get_dma_params); + +/** + * DMA start - starts the dma on the channel passed + * Arguments: + * lch - logical channel number + */ +int davinci_start_dma(int lch) +{ + int ret = 0; + u32 mask; + + if (dma_is_edmach(lch)) { + /* Check is EDMA channel with event association */ + if (!edmach_has_event(lch)) { + DBG("ESR=%x\n", dma_read(EDMA_SH_ESR(0))); + + if (lch < 32) + SET_REG_VAL(1 << lch, EDMA_SH_ESR(0)); + else + SET_REG_VAL(1 << (lch - 32), EDMA_SH_ESRH(0)); + + return ret; + } + + DBG("ER=%d\n", dma_read(EDMA_SH_ER(0))); + if (lch < 32) { + mask = 1 << lch; + /* Clear any pedning error */ + SET_REG_VAL(mask, EDMA_EMCR); + /* Clear any SER */ + SET_REG_VAL(mask, EDMA_SH_SECR(0)); + SET_REG_VAL(mask, EDMA_SH_EESR(0)); + } else { + mask = 1 << (lch - 32); + /* Clear any pedning error */ + SET_REG_VAL(mask, EDMA_EMCRH); + /* Clear any SER */ + SET_REG_VAL(mask, EDMA_SH_SECRH(0)); + SET_REG_VAL(mask, EDMA_SH_EESRH(0)); + } + DBG("EER=%d\n", dma_read(EDMA_SH_EER(0))); + } else if (dma_is_qdmach(lch)) { + SET_REG_VAL(1 << (lch - EDMA_NUM_DMACH), EDMA_SH_QEESR(0)); + } else { + /* for Slave Channels */ + ret = -EINVAL; + } + + return ret; +} +EXPORT_SYMBOL(davinci_start_dma); + +/** + * DMA stop - stops the dma on the channel passed + * Arguments: + * lch - logical channel number + */ +void davinci_stop_dma(int lch) +{ + u32 reg, mask; + + if (lch < EDMA_NUM_DMACH) { + /* Check is EDMA channel with event association */ + if (!edmach_has_event(lch)) + return; + + if (lch < 32) { + reg = EDMA_SH_EECR(0); + mask = 1 << lch; + CLEAR_EVENT(mask, EDMA_SH_ER(0), EDMA_SH_ECR(0)); + CLEAR_EVENT(mask, EDMA_SH_SER(0), EDMA_SH_SECR(0)); + CLEAR_EVENT(mask, EDMA_EMR, EDMA_EMCR); + } else { + reg = EDMA_SH_EECRH(0); + mask = 1 << (lch - 32); + CLEAR_EVENT(mask, EDMA_SH_ERH(0), EDMA_SH_ECRH(0)); + CLEAR_EVENT(mask, EDMA_SH_SERH(0), EDMA_SH_SECRH(0)); + CLEAR_EVENT(mask, EDMA_EMRH, EDMA_EMCRH); + } + SET_REG_VAL(mask, reg); + DBG("EER=%d\n", dma_read(EDMA_SH_EER(0))); + } else if (dma_is_qdmach(lch)) { + /* for QDMA channels */ + SET_REG_VAL(1 << (lch - EDMA_NUM_DMACH), EDMA_QEECR); + DBG("QER=%d\n", dma_read(EDMA_QER)); + DBG("QEER=%d\n", dma_read(EDMA_QEER)); + } else if ((lch >= (EDMA_NUM_DMACH + EDMA_NUM_QDMACH)) && + lch < EDMA_NUM_PARAMENTRY) { + /* for slaveChannels */ + CLEAR_REG_VAL(0xffff, EDMA_PARAM_LINK_BCNTRLD(lch)); + SET_REG_VAL(0xffff, EDMA_PARAM_LINK_BCNTRLD(lch)); + } +} +EXPORT_SYMBOL(davinci_stop_dma); + +/** + * DMA channel link - link the two logical channels passed through by linking + * the link field of head to the param pointed by the + * lch_queue. + * Arguments: + * lch_head - logical channel number, in which the link field is linked + * to the param pointed to by lch_queue + * lch_queue - logical channel number or the param entry number, which is + * to be linked to the lch_head + */ +void davinci_dma_link_lch(int lch_head, int lch_queue) +{ + u16 link; + u32 reg; + + if (dma_is_qdmach(lch_head)) + lch_head = qdma2param_map[lch_head - EDMA_NUM_DMACH]; + + if (dma_is_qdmach(lch_queue)) + lch_queue = qdma2param_map[lch_queue - EDMA_NUM_DMACH]; + + if ((lch_head >= 0 && lch_head < EDMA_NUM_PARAMENTRY) && + (lch_queue >= 0 && lch_queue < EDMA_NUM_PARAMENTRY)) { + /* program LINK */ + link = (u16) + IO_ADDRESS(EDMA_PARAM_OPT(dma_chan[lch_queue].param_no)); + reg = EDMA_PARAM_LINK_BCNTRLD(dma_chan[lch_head].param_no); + CLEAR_REG_VAL(0xffff, reg); + SET_REG_VAL(link, reg); + } +} +EXPORT_SYMBOL(davinci_dma_link_lch); + +/** + * DMA channel unlink - unlink the two logical channels passed through by + * setting the link field of head to 0xffff. + * Arguments: + * lch_head - logical channel number, from which the link field is + * to be removed + * lch_queue - logical channel number or the param entry number, + * which is to be unlinked from lch_head + */ +void davinci_dma_unlink_lch(int lch_head, int lch_queue) +{ + u32 reg; + + if (dma_is_qdmach(lch_head)) + lch_head = qdma2param_map[lch_head - EDMA_NUM_DMACH]; + + if (dma_is_qdmach(lch_queue)) + lch_queue = qdma2param_map[lch_queue - EDMA_NUM_DMACH]; + + if ((lch_head >= 0 && lch_head < EDMA_NUM_PARAMENTRY) && + (lch_queue >= 0 && lch_queue < EDMA_NUM_PARAMENTRY)) { + reg = EDMA_PARAM_LINK_BCNTRLD(dma_chan[lch_head].param_no); + SET_REG_VAL(0xffff, reg); + } +} +EXPORT_SYMBOL(davinci_dma_unlink_lch); + +/** + * DMA clean channel - cleans Paramentry and bring back EDMA to initial state + * if media has been removed before EDMA has finished. It is usedful for + * removable media. + * Arguments: + * lch - logical channel number + */ +void davinci_clean_channel(int lch) +{ + u32 mask; + + if (lch < 32) { + DBG("EMR =%d\n", dma_read(EDMA_EMR)); + mask = 1 << lch; + SET_REG_VAL(mask, EDMA_SH_ECR(0)); + /* Clear the corresponding EMR bits */ + SET_REG_VAL(mask, EDMA_EMCR); + /* Clear any SER */ + SET_REG_VAL(mask, EDMA_SH_SECR(0)); + } else { + DBG("EMRH =%d\n", dma_read(EDMA_EMRH)); + mask = 1 << (lch - 32); + SET_REG_VAL(mask, EDMA_SH_ECRH(0)); + /* Clear the corresponding EMRH bits */ + SET_REG_VAL(mask, EDMA_EMCRH); + /* Clear any SER */ + SET_REG_VAL(mask, EDMA_SH_SECRH(0)); + } + + SET_REG_VAL((1 << 16) | 0x3, EDMA_CCERRCLR); +} +EXPORT_SYMBOL(davinci_clean_channel); + +/** + * DMA transfer position - returns the current transfer points for the dma + * source and destination + * Arguments: + * lch - logical channel number + * src - source port position + * dst - destination port position + */ +void davinci_dma_getposition(int lch, dma_addr_t *src, dma_addr_t *dst) +{ + struct paramentry_descriptor temp; + + davinci_get_dma_params(lch, &temp); + if (src != NULL) + *src = temp.src; + if (dst != NULL) + *dst = temp.dst; +} +EXPORT_SYMBOL(davinci_dma_getposition); + +static int __init davinci_dma_init(void) +{ + int i, ret; + u32 mask; + + DBG("DMA BASE ADDR=%x\n", (unsigned int)IO_ADDRESS(EDMA_BASE)); + + memset((void *)IO_ADDRESS(EDMA_PARAM_OPT(0)), 0x00, EDMA_PARAM_SIZE); + + /* Event queue to TC mapping */ + for (i = 0; i < EDMA_NUM_EVQUE; i++) { + mask = evtqueue_tc_map[i][0] << 2; + CLEAR_REG_VAL(0x7 << mask, EDMA_QUETCMAP); + mask = (evtqueue_tc_map[i][1] & 0x7) << mask; + SET_REG_VAL(mask, EDMA_QUETCMAP); + } + + /* Assign priority to event queue */ + for (i = 0; i < EDMA_NUM_EVQUE; i++) { + mask = evtqueue_priority_map[i][0] << 2; + CLEAR_REG_VAL(0x7 << mask, EDMA_QUEPRI); + mask = (evtqueue_priority_map[i][1] & 0x7) << mask; + SET_REG_VAL(mask, EDMA_QUEPRI); + } + + for (i = 0; i < EDMA_NUM_REGIONS; i++) { + dma_write(0x0, EDMA_DRAE(i)); + dma_write(0x0, EDMA_DRAEH(i)); + dma_write(0x0, EDMA_QRAE(i)); + } + + ret = request_irq(IRQ_CCINT0, davinci_dma_irq_handler, 0, "EDMA", NULL); + if (ret) { + printk(KERN_ERR "unable to request IRQ %d for DMA (error %d)\n", + IRQ_CCINT0, ret); + DBG("request_irq failed\n"); + return ret; + } + + ret = request_irq(IRQ_CCERRINT, davinci_dma_ccerr_handler, 0, + "EDMA CC Err", NULL); + if (ret) { + printk(KERN_ERR "unable to request IRQ %d for DMA (error %d)\n", + IRQ_CCERRINT, ret); + free_irq(IRQ_CCINT0, NULL); + return ret; + } + + /* TODO: add cpu_is_xxx() check for different Davinci SoCs */ + edma2event_map[0] = DM644X_DMACH2EVENT_MAP0; + edma2event_map[1] = DM644X_DMACH2EVENT_MAP1; + + return 0; +} + +arch_initcall(davinci_dma_init); Index: linux-2.6.25-rc1/include/asm-arm/arch-davinci/edma.h =================================================================== --- /dev/null +++ linux-2.6.25-rc1/include/asm-arm/arch-davinci/edma.h @@ -0,0 +1,370 @@ +/* + * TI DaVinci DMA Support + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (c) 2007, MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_EDMA_H +#define __ASM_ARCH_EDMA_H + +#include + +/* + * DMA driver for DaVinci + * DMA driver for Davinci abstractes each ParamEntry as a Logical DMA channel + * for the user.So on Davinci the user can request 128 DAM channels + * + * Actual Physical DMA channels = 64 EDMA channels + 8 QDMA channels + * + * On davinci user can request for two kinds of Logical DMA channels + * DMA MasterChannel -> ParamEntry which is associated with a DMA channel. + * On Davinci there are (64 + 8) MasterChanneles + * MasterChannel can be triggered by an event or manually + * + * DMA SlaveChannel -> ParamEntry which is not associated with DMA cahnnel but + * which can be used to associate with MasterChannel. + * On Davinci there are (128-(64 + 8)) SlaveChannels + * SlaveChannel can only be triggered by a MasterChannel + */ + +#define EDMA_BASE DAVINCI_DMA_3PCC_BASE + +#define EDMA_REV (EDMA_BASE + 0x0000) +#define EDMA_CCCFG (EDMA_BASE + 0x0004) +#define EDMA_QCHMAP(n) (EDMA_BASE + 0x0200 + ((n) << 2)) +#define EDMA_DMAQNUM(n) (EDMA_BASE + 0x0240 + ((n) << 2)) +#define EDMA_QDMAQNUM (EDMA_BASE + 0x0260) +#define EDMA_QUETCMAP (EDMA_BASE + 0x0280) +#define EDMA_QUEPRI (EDMA_BASE + 0x0284) +#define EDMA_EMR (EDMA_BASE + 0x0300) +#define EDMA_EMRH (EDMA_BASE + 0x0304) +#define EDMA_EMCR (EDMA_BASE + 0x0308) +#define EDMA_EMCRH (EDMA_BASE + 0x030C) +#define EDMA_QEMR (EDMA_BASE + 0x0310) +#define EDMA_QEMCR (EDMA_BASE + 0x0314) +#define EDMA_CCERR (EDMA_BASE + 0x0318) +#define EDMA_CCERRCLR (EDMA_BASE + 0x031C) +#define EDMA_EEVAL (EDMA_BASE + 0x0320) +#define EDMA_DRAE(n) (EDMA_BASE + 0x0340 + ((n) << 3)) +#define EDMA_DRAEH(n) (EDMA_BASE + 0x0344 + ((n) << 3)) +#define EDMA_QRAE(n) (EDMA_BASE + 0x0380 + ((n) << 2)) +#define EDMA_QEE0(n) (EDMA_BASE + 0x0400 + ((n) << 2)) +#define EDMA_QEE1(n) (EDMA_BASE + 0x0440 + ((n) << 2)) +#define EDMA_QSTAT0 (EDMA_BASE + 0x0600) +#define EDMA_QSTAT1 (EDMA_BASE + 0x0604) +#define EDMA_QWMTHRA (EDMA_BASE + 0x0620) +#define EDMA_QWMTHRB (EDMA_BASE + 0x0624) +#define EDMA_CCSTAT (EDMA_BASE + 0x0640) +#define EDMA_AETCTL (EDMA_BASE + 0x0700) +#define EDMA_AETSTAT (EDMA_BASE + 0x0704) +#define EDMA_AETCMD (EDMA_BASE + 0x0708) +#define EDMA_ER (EDMA_BASE + 0x1000) +#define EDMA_ERH (EDMA_BASE + 0x1004) +#define EDMA_ECR (EDMA_BASE + 0x1008) +#define EDMA_ECRH (EDMA_BASE + 0x100C) +#define EDMA_ESR (EDMA_BASE + 0x1010) +#define EDMA_ESRH (EDMA_BASE + 0x1014) +#define EDMA_CER (EDMA_BASE + 0x1018) +#define EDMA_CERH (EDMA_BASE + 0x101C) +#define EDMA_EER (EDMA_BASE + 0x1020) +#define EDMA_EERH (EDMA_BASE + 0x1024) +#define EDMA_EECR (EDMA_BASE + 0x1028) +#define EDMA_EECRH (EDMA_BASE + 0x102C) +#define EDMA_EESR (EDMA_BASE + 0x1030) +#define EDMA_EESRH (EDMA_BASE + 0x1034) +#define EDMA_SER (EDMA_BASE + 0x1038) +#define EDMA_SERH (EDMA_BASE + 0x103C) +#define EDMA_SECR (EDMA_BASE + 0x1040) +#define EDMA_SECRH (EDMA_BASE + 0x1044) +#define EDMA_IER (EDMA_BASE + 0x1050) +#define EDMA_IERH (EDMA_BASE + 0x1054) +#define EDMA_IECR (EDMA_BASE + 0x1058) +#define EDMA_IECRH (EDMA_BASE + 0x105C) +#define EDMA_IESR (EDMA_BASE + 0x1060) +#define EDMA_IESRH (EDMA_BASE + 0x1064) +#define EDMA_IPR (EDMA_BASE + 0x1068) +#define EDMA_IPRH (EDMA_BASE + 0x106C) +#define EDMA_ICR (EDMA_BASE + 0x1070) +#define EDMA_ICRH (EDMA_BASE + 0x1074) +#define EDMA_IEVAL (EDMA_BASE + 0x1078) +#define EDMA_QER (EDMA_BASE + 0x1080) +#define EDMA_QEER (EDMA_BASE + 0x1084) +#define EDMA_QEECR (EDMA_BASE + 0x1088) +#define EDMA_QEESR (EDMA_BASE + 0x108C) +#define EDMA_QSER (EDMA_BASE + 0x1090) +#define EDMA_QSECR (EDMA_BASE + 0x1094) + +/* Shadow Registers */ +#define EDMA_SHADOW_BASE (EDMA_BASE + 0x2000) +#define EDMA_SHADOW(offset, n) (EDMA_SHADOW_BASE + offset + (n << 9)) + +#define EDMA_SH_ER(n) EDMA_SHADOW(0x00, n) +#define EDMA_SH_ERH(n) EDMA_SHADOW(0x04, n) +#define EDMA_SH_ECR(n) EDMA_SHADOW(0x08, n) +#define EDMA_SH_ECRH(n) EDMA_SHADOW(0x0C, n) +#define EDMA_SH_ESR(n) EDMA_SHADOW(0x10, n) +#define EDMA_SH_ESRH(n) EDMA_SHADOW(0x14, n) +#define EDMA_SH_CER(n) EDMA_SHADOW(0x18, n) +#define EDMA_SH_CERH(n) EDMA_SHADOW(0x1C, n) +#define EDMA_SH_EER(n) EDMA_SHADOW(0x20, n) +#define EDMA_SH_EERH(n) EDMA_SHADOW(0x24, n) +#define EDMA_SH_EECR(n) EDMA_SHADOW(0x28, n) +#define EDMA_SH_EECRH(n) EDMA_SHADOW(0x2C, n) +#define EDMA_SH_EESR(n) EDMA_SHADOW(0x30, n) +#define EDMA_SH_EESRH(n) EDMA_SHADOW(0x34, n) +#define EDMA_SH_SER(n) EDMA_SHADOW(0x38, n) +#define EDMA_SH_SERH(n) EDMA_SHADOW(0x3C, n) +#define EDMA_SH_SECR(n) EDMA_SHADOW(0x40, n) +#define EDMA_SH_SECRH(n) EDMA_SHADOW(0x44, n) +#define EDMA_SH_IER(n) EDMA_SHADOW(0x50, n) +#define EDMA_SH_IERH(n) EDMA_SHADOW(0x54, n) +#define EDMA_SH_IECR(n) EDMA_SHADOW(0x58, n) +#define EDMA_SH_IECRH(n) EDMA_SHADOW(0x5C, n) +#define EDMA_SH_IESR(n) EDMA_SHADOW(0x60, n) +#define EDMA_SH_IESRH(n) EDMA_SHADOW(0x64, n) +#define EDMA_SH_IPR(n) EDMA_SHADOW(0x68, n) +#define EDMA_SH_IPRH(n) EDMA_SHADOW(0x6C, n) +#define EDMA_SH_ICR(n) EDMA_SHADOW(0x70, n) +#define EDMA_SH_ICRH(n) EDMA_SHADOW(0x74, n) +#define EDMA_SH_IEVAL(n) EDMA_SHADOW(0x78, n) +#define EDMA_SH_QER(n) EDMA_SHADOW(0x80, n) +#define EDMA_SH_QEER(n) EDMA_SHADOW(0x84, n) +#define EDMA_SH_QEECR(n) EDMA_SHADOW(0x88, n) +#define EDMA_SH_QEESR(n) EDMA_SHADOW(0x8C, n) +#define EDMA_SH_QSER(n) EDMA_SHADOW(0x90, n) +#define EDMA_SH_QSECR(n) EDMA_SHADOW(0x94, n) + +/* Paramentry Registers */ +#define EDMA_PARAM_BASE (EDMA_BASE + 0x4000) +#define EDMA_PARAM_SIZE 0x1000 +#define EDMA_PARAM(offset, n) (EDMA_PARAM_BASE + offset + (n << 5)) + +#define EDMA_PARAM_OPT(n) EDMA_PARAM(0x00, n) +#define EDMA_PARAM_SRC(n) EDMA_PARAM(0x04, n) +#define EDMA_PARAM_A_B_CNT(n) EDMA_PARAM(0x08, n) +#define EDMA_PARAM_DST(n) EDMA_PARAM(0x0C, n) +#define EDMA_PARAM_SRC_DST_BIDX(n) EDMA_PARAM(0x10, n) +#define EDMA_PARAM_LINK_BCNTRLD(n) EDMA_PARAM(0x14, n) +#define EDMA_PARAM_SRC_DST_CIDX(n) EDMA_PARAM(0x18, n) +#define EDMA_PARAM_CCNT(n) EDMA_PARAM(0x1C, n) + +/* + * Paramentry descriptor + */ +struct paramentry_descriptor { + unsigned int opt; + unsigned int src; + unsigned int a_b_cnt; + unsigned int dst; + unsigned int src_dst_bidx; + unsigned int link_bcntrld; + unsigned int src_dst_cidx; + unsigned int ccnt; +}; + + +#define dma_write(val, addr) davinci_writel(val, addr) +#define dma_read(addr) davinci_readl(addr) + +#define SET_REG_VAL(mask, reg) do { \ + dma_write(dma_read(reg) | (mask), reg); \ +} while (0) + +#define CLEAR_REG_VAL(mask, reg) do { \ + dma_write(dma_read(reg) & ~(mask), reg); \ +} while (0) + +#define CLEAR_EVENT(mask, event, reg) do { \ + if (dma_read(event) & mask) \ + SET_REG_VAL(mask, reg); \ +} while (0) + + +#define EDMA_XFER_COMPLETION_INT IRQ_CCINT0 +#define EDMA_CC_ERROR_INT IRQ_CCERRINT +#define EDMA_TC0_ERROR_INT IRQ_TCERRINT0 +#define EDMA_TC1_ERROR_INT IRQ_TCERRINT + +#define SAM (1 << 0) +#define DAM (1 << 1) +#define SYNCDIM (1 << 2) +#define STATIC (1 << 3) +#define EDMA_FWID (0x7 << 8) +#define TCCMODE (0x1 << 11) +#define TCC (0x3f << 12) +#define WIMODE (0x1 << 19) +#define TCINTEN (1 << 20) +#define ITCINTEN (1 << 21) +#define TCCHEN (1 << 22) +#define ITCCHEN (1 << 23) +#define SECURE (1 << 30) +#define PRIV (1 << 31) + +#define TRWORD (0x7 << 2) +#define PAENTRY (0x1ff << 5) +/* if changing the QDMA_TRWORD do appropriate change in davinci_start_dma */ +#define QDMA_TRWORD (7 & 0x7) + +#define EDMA_NUM_DMACH 64 +#define EDMA_NUM_QDMACH 8 +#define dma_is_edmach(lch) ((lch >= 0) && (lch < EDMA_NUM_DMACH)) +#define dma_is_qdmach(lch) ((lch >= EDMA_NUM_DMACH) && \ + (lch < (EDMA_NUM_DMACH + EDMA_NUM_QDMACH))) + +#define EDMA_NUM_PARAMENTRY 128 +#define EDMA_NUM_EVQUE 2 +#define EDMA_NUM_REGIONS 4 + +#define TCC_ANY -1 +#define DMACH_ANY -1 +#define PARAM_ANY -2 + + +#define edmach_has_event(lch) (edma2event_map[lch >> 5] & (1 << (lch % 32))) + +#define dmach_is_valid(lch) (dma2arm_map[lch >> 5] & (1 << (lch % 32))) +#define param_is_valid(lch) (param2arm_map[lch >> 5] & (1 << (lch % 32))) + +#define param_reserve(lch) do { \ + param_entry_reserved[lch >> 5] |= (1 << (lch % 32)); \ +} while (0) +#define param_free(lch) do { \ + param_entry_reserved[lch >> 5] &= ~(1 << (lch % 32)); \ +} while (0) +#define param_is_free(lch) \ + (!(param_entry_reserved[lch >> 5] & (1 << (lch % 32)))) + +#define interrupt_reserve(lch) do { \ + dma_intr_reseved[lch >> 5] |= (1 << (lch % 32));\ +} while (0) +#define interrupt_free(lch) do { \ + dma_intr_reseved[lch >> 5] &= ~(1 << (lch % 32)); \ +} while (0) +#define interrupt_is_free(lch) \ + (!(dma_intr_reseved[lch >> 5] & (1 << (lch % 32)))) + +#define DM644X_DMACH2EVENT_MAP0 0x3DFF0FFC +#define DM644X_DMACH2EVENT_MAP1 0x007F1FFF + +enum dm644x_edma_ch { + DM644X_DMACH_MCBSP_TX = 2, + DM644X_DMACH_MCBSP_RX, + DM644X_DMACH_VPSS_HIST, + DM644X_DMACH_VPSS_H3A, + DM644X_DMACH_VPSS_PRVU, + DM644X_DMACH_VPSS_RSZ, + DM644X_DMACH_IMCOP_IMXINT, + DM644X_DMACH_IMCOP_VLCDINT, + DM644X_DMACH_IMCO_PASQINT, + DM644X_DMACH_IMCOP_DSQINT, + DM644X_DMACH_SPI_SPIX = 16, + DM644X_DMACH_SPI_SPIR, + DM644X_DMACH_UART0_URXEVT0, + DM644X_DMACH_UART0_UTXEVT0, + DM644X_DMACH_UART1_URXEVT1, + DM644X_DMACH_UART1_UTXEVT1, + DM644X_DMACH_UART2_URXEVT2, + DM644X_DMACH_UART2_UTXEVT2, + DM644X_DMACH_MEMSTK_MSEVT, + DM644X_DMACH_MMCRXEVT = 26, + DM644X_DMACH_MMCTXEVT, + DM644X_DMACH_I2C_ICREVT, + DM644X_DMACH_I2C_ICXEVT, + DM644X_DMACH_GPIO_GPINT0 = 32, + DM644X_DMACH_GPIO_GPINT1, + DM644X_DMACH_GPIO_GPINT2, + DM644X_DMACH_GPIO_GPINT3, + DM644X_DMACH_GPIO_GPINT4, + DM644X_DMACH_GPIO_GPINT5, + DM644X_DMACH_GPIO_GPINT6, + DM644X_DMACH_GPIO_GPINT7, + DM644X_DMACH_GPIO_GPBNKINT0, + DM644X_DMACH_GPIO_GPBNKINT1, + DM644X_DMACH_GPIO_GPBNKINT2, + DM644X_DMACH_GPIO_GPBNKINT3, + DM644X_DMACH_GPIO_GPBNKINT4, + DM644X_DMACH_TIMER0_TINT0 = 48, + DM644X_DMACH_TIMER1_TINT1, + DM644X_DMACH_TIMER2_TINT2, + DM644X_DMACH_TIMER3_TINT3, + DM644X_DMACH_PWM0, + DM644X_DMACH_PWM1, + DM644X_DMACH_PWM2, +}; + +enum dm644x_qdma_ch { + QDMACH0 = EDMA_NUM_DMACH, + QDMACH1, + QDMACH2, + QDMACH3, + QDMACH4, + QDMACH5, + QDMACH6 = 71, + QDMACH7 +}; + +/* ch_status paramater of callback function possible values */ +enum edma_status { + DMA_COMPLETE = 1, + DMA_CC_ERROR, + DMA_TC1_ERROR, + DMA_TC2_ERROR +}; + +enum address_mode { + INCR = 0, + FIFO = 1 +}; + +enum fifo_width { + W8BIT = 0, + W16BIT = 1, + W32BIT = 2, + W64BIT = 3, + W128BIT = 4, + W256BIT = 5 +}; + +enum dma_event_q { + EVENTQ_0 = 0, + EVENTQ_1 = 1, + EVENTQ_DEFAULT = -1 +}; + +enum sync_dimension { + ASYNC = 0, + ABSYNC = 1 +}; + +int davinci_request_dma(int dev_id, + const char *dev_name, + void (*callback) (int lch, unsigned short ch_status, + void *data), void *data, int *lch, + int *tcc, enum dma_event_q +); +void davinci_set_dma_src_params(int lch, u32 src_port, + enum address_mode mode, enum fifo_width); +void davinci_set_dma_dest_params(int lch, u32 dest_port, + enum address_mode mode, enum fifo_width); +void davinci_set_dma_src_index(int lch, u16 srcbidx, u16 srccidx); +void davinci_set_dma_dest_index(int lch, u16 destbidx, u16 destcidx); +void davinci_set_dma_transfer_params(int lch, u16 acnt, u16 bcnt, u16 ccnt, + u16 bcntrld, + enum sync_dimension sync_mode); +void davinci_set_dma_params(int lch, struct paramentry_descriptor *d); +void davinci_get_dma_params(int lch, struct paramentry_descriptor *d); +int davinci_start_dma(int lch); +void davinci_stop_dma(int lch); +void davinci_dma_link_lch(int lch_head, int lch_queue); +void davinci_dma_unlink_lch(int lch_head, int lch_queue); +void davinci_free_dma(int lch); +void davinci_dma_getposition(int lch, dma_addr_t *src, dma_addr_t *dst); + +#endif /* __ASM_ARCH_EDMA_H */ Index: linux-2.6.25-rc1/arch/arm/mach-davinci/Makefile =================================================================== --- linux-2.6.25-rc1.orig/arch/arm/mach-davinci/Makefile +++ linux-2.6.25-rc1/arch/arm/mach-davinci/Makefile @@ -5,7 +5,7 @@ # Common objects obj-y := time.o irq.o clock.o serial.o io.o id.o psc.o \ - gpio.o mux.o mux_cfg.o devices.o + gpio.o mux.o mux_cfg.o devices.o dma.o # Board specific obj-$(CONFIG_MACH_DAVINCI_EVM) += board-evm.o Index: linux-2.6.25-rc1/include/asm-arm/arch-davinci/dma.h =================================================================== --- linux-2.6.25-rc1.orig/include/asm-arm/arch-davinci/dma.h +++ linux-2.6.25-rc1/include/asm-arm/arch-davinci/dma.h @@ -13,4 +13,6 @@ #define MAX_DMA_ADDRESS 0xffffffff +#include "edma.h" + #endif /* __ASM_ARCH_DMA_H */