📄 dma.c
字号:
(DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { if (free_intr_no < 32) { ptr_edmacc_regs->dra[0].drae = ptr_edmacc_regs->dra[0].drae | (1 << free_intr_no); } else { ptr_edmacc_regs->dra[0].draeh = ptr_edmacc_regs->dra[0]. draeh | (1 << (free_intr_no - 32)); } } if (free_intr_no >= 0 && free_intr_no < 64) { (free_intr_no < 32) ? (ptr_edmacc_regs->shadow[0].iesr |= (1UL << free_intr_no)) : (ptr_edmacc_regs->shadow[0].iesrh |= (1UL << (free_intr_no - 32))); intr_data[free_intr_no].callback = callback; intr_data[free_intr_no].data = data; } return free_intr_no;}/****************************************************************************** * * Free the dma interrupt: Releases the dma interrupt on the channel * * Arguments: * intr_no - interrupt number on the channel to be released or freed out * * Return: N/A * *****************************************************************************/static void free_dma_interrupt(int intr_no){ if (intr_no >= 0 && intr_no < 64) { (intr_no < 32) ? (ptr_edmacc_regs->shadow[0].icr |= (1UL << (intr_no))) : (ptr_edmacc_regs-> shadow[0].icrh |= (1UL << (intr_no - 32))); LOCK; /* Global structure and could be modified by several task */ dma_intr_use_status[intr_no / 32] |= (1 << (intr_no % 32)); UNLOCK; intr_data[intr_no].callback = NULL; intr_data[intr_no].data = NULL; }}/****************************************************************************** * * DMA interrupt handler * *****************************************************************************/static void dma_irq_handler(void){ int i; unsigned int cnt; cnt = 0; if ((ptr_edmacc_regs->shadow[0].ipr == 0) && (ptr_edmacc_regs->shadow[0].iprh == 0)) return; while (1) { if (ptr_edmacc_regs->shadow[0].ipr) { dev_dbg(&edma_dev.dev, "IPR =%d\r\n", ptr_edmacc_regs->shadow[0].ipr); for (i = 0; i < 32; i++) { if (ptr_edmacc_regs->shadow[0].ipr & (1 << i)) { /* Clear the corresponding IPR bits */ ptr_edmacc_regs->shadow[0].icr |= (1 << i); if (intr_data[i].callback) { intr_data[i].callback(i, DMA_COMPLETE, intr_data [i].data); } } } } else if (ptr_edmacc_regs->shadow[0].iprh) { dev_dbg(&edma_dev.dev, "IPRH =%d\r\n", ptr_edmacc_regs->shadow[0].iprh); for (i = 0; i < 32; i++) { if (ptr_edmacc_regs->shadow[0].iprh & (1 << i)) { /* Clear the corresponding IPR bits */ ptr_edmacc_regs->shadow[0].icrh |= (1 << i); if (intr_data[32 + i].callback) { intr_data[32 + i].callback(32 + i, DMA_COMPLETE, intr_data [32 + i]. data); } } } } if ((ptr_edmacc_regs->shadow[0].ipr == 0) && (ptr_edmacc_regs->shadow[0].iprh == 0)) { break; } cnt++; if (cnt > 10) { break; } } ptr_edmacc_regs->shadow[0].ieval = 0x1;}/****************************************************************************** * * DMA error interrupt handler * *****************************************************************************/static void dma_ccerr_handler(void){ int i; unsigned int cnt; cnt = 0; if ((ptr_edmacc_regs->emr == 0) && (ptr_edmacc_regs->emr == 0) && (ptr_edmacc_regs->qemr == 0) && (ptr_edmacc_regs->ccerr == 0)) return; while (1) { if (ptr_edmacc_regs->emr) { dev_dbg(&edma_dev.dev, "EMR =%d\r\n", ptr_edmacc_regs->emr); for (i = 0; i < 32; i++) { if (ptr_edmacc_regs->emr & (1 << i)) { /* Clear the corresponding EMR bits */ ptr_edmacc_regs->emcr |= (1 << i); /* Clear any SER */ ptr_edmacc_regs->shadow[0].secr |= (1 << i); if (intr_data[i].callback) { intr_data[i].callback(i, DMA_CC_ERROR, intr_data [i].data); } } } } else if (ptr_edmacc_regs->emrh) { dev_dbg(&edma_dev.dev, "EMRH =%d\r\n", ptr_edmacc_regs->emrh); for (i = 0; i < 32; i++) { if (ptr_edmacc_regs->emrh & (1 << i)) { /* Clear the corresponding IPR bits */ ptr_edmacc_regs->emcrh |= (1 << i); /* Clear any SER */ ptr_edmacc_regs->shadow[0].secrh |= (1 << i); if (intr_data[i].callback) { intr_data[i].callback(i, DMA_CC_ERROR, intr_data [i].data); } } } } else if (ptr_edmacc_regs->qemr) { dev_dbg(&edma_dev.dev, "QEMR =%d\r\n", ptr_edmacc_regs->qemr); for (i = 0; i < 8; i++) { if (ptr_edmacc_regs->qemr & (1 << i)) { /* Clear the corresponding IPR bits */ ptr_edmacc_regs->qemcr |= (1 << i); ptr_edmacc_regs->shadow[0].qsecr |= (1 << i); } } } else if (ptr_edmacc_regs->ccerr) { dev_dbg(&edma_dev.dev, "CCERR =%d\r\n", ptr_edmacc_regs->ccerr); for (i = 0; i < 8; i++) { if (ptr_edmacc_regs->ccerr & (1 << i)) { /* Clear the corresponding IPR bits */ ptr_edmacc_regs->ccerrclr |= (1 << i); } } } if ((ptr_edmacc_regs->emr == 0) && (ptr_edmacc_regs->emrh == 0) && (ptr_edmacc_regs->qemr == 0) && (ptr_edmacc_regs->ccerr == 0)) { break; } cnt++; if (cnt > 10) { break; } } ptr_edmacc_regs->eeval = 0x1;}/****************************************************************************** * * DMA error interrupt handler * *****************************************************************************/static void dma_tc1err_handler(void){}/****************************************************************************** * * DMA error interrupt handler * *****************************************************************************/static void dma_tc2err_handler(void){}/****************************************************************************** * * DMA initialisation on davinci * *****************************************************************************/int __init arch_dma_init(void){ int i; edma_driver.name = "edma"; edma_dev.name = "dma"; edma_dev.id = -1; edma_dev.dev.driver = &edma_driver; ptr_edmacc_regs = get_edma_base(); dev_dbg(&edma_dev.dev, "DMA REG BASE ADDR=%x\n", ptr_edmacc_regs); memset(dma_chan, 0x00, sizeof(dma_chan)); memset((void *)&(ptr_edmacc_regs->paramentry[0]), 0x00, sizeof(ptr_edmacc_regs->paramentry)); i = 0; /* Channel to queue mapping */ while (channel_queue_mapping[i][0] != -1) { map_dmach_queue(channel_queue_mapping[i][0], channel_queue_mapping[i][1]); i++; } i = 0; /* Event queue to TC mapping */ while (queue_tc_mapping[i][0] != -1) { map_queue_tc(queue_tc_mapping[i][0], queue_tc_mapping[i][1]); i++; } i = 0; /* Event queue priority mapping */ while (queue_priority_mapping[i][0] != -1) { assign_priority_to_queue(queue_priority_mapping[i][0], queue_priority_mapping[i][1]); i++; } for (i = 0; i < DAVINCI_EDMA_NUM_REGIONS; i++) { ptr_edmacc_regs->dra[i].drae = 0x0; ptr_edmacc_regs->dra[i].draeh = 0x0; ptr_edmacc_regs->qrae[i] = 0x0; } LOCK_INIT; return 0;}/****************************************************************************** * * DMA channel requests: Requests for the dma device passed if it is free * * Arguments: * dev_id - request for the param entry device id * dev_name - device name * callback - pointer to the channel callback. * Arguments: * lch - channel no, which is the IPR bit position, * indicating from which channel the interrupt arised. * data - channel private data, which is received as one of the * arguments in davinci_request_dma. * data - private data for the channel to be requested, which is used to * pass as a parameter in the callback function * in irq handler. * lch - contains the device id allocated * tcc - Transfer Completion Code, used to set the IPR register bit * after transfer completion on that channel. * eventq_no - Event Queue no to which the channel will be associated with * (valied only if you are requesting for a DMA MasterChannel) * Values : 0 to 7 * -1 for Default queue * INPUT: dev_id * OUTPUT: *dma_ch_out * * Return: zero on success, or corresponding error no on failure * *****************************************************************************/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 eventq_no){ int ret_val = 0, i = 0; static int req_flag = 0; int temp_ch = 0; /* checking the ARM side events */ if (dev_id >= 0 && (dev_id < DAVINCI_EDMA_NUM_DMACH)) { if (!(edma_channels_arm[dev_id / 32] & (0x1 << (dev_id % 32)))) { dev_dbg(&edma_dev.dev, "dev_id = %d not supported on ARM side\r\n", dev_id); return -EINVAL; } } else if (dev_id >= DAVINCI_EDMA_NUM_DMACH && dev_id <= (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { if (!(qdma_channels_arm[0] & (0x1 << (dev_id - DAVINCI_EDMA_NUM_DMACH)))) { dev_dbg(&edma_dev.dev, "dev_id = %d not supported on ARM side\r\n", dev_id); return -EINVAL; } } if ((dev_id != DAVINCI_DMA_CHANNEL_ANY) && (dev_id != DAVINCI_EDMA_PARAM_ANY)) { if (dev_id >= DAVINCI_EDMA_NUM_DMACH && dev_id < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH) ) { ptr_edmacc_regs->qrae[0] = ptr_edmacc_regs->qrae[0] | (1 << (dev_id - DAVINCI_EDMA_NUM_DMACH)); } else { if (dev_id < 32) { ptr_edmacc_regs->dra[0].drae = ptr_edmacc_regs->dra[0].drae | (1 << dev_id); } else { ptr_edmacc_regs->dra[0].draeh = ptr_edmacc_regs->dra[0].draeh | (1 << (dev_id - 32)); } } } if (!req_flag) { if (register_dma_interrupts (dma_irq_handler, dma_ccerr_handler, dma_tc1err_handler, dma_tc2err_handler)) { dev_dbg(&edma_dev.dev, "register_dma_interrupts failed\r\n"); return -EINVAL; } else req_flag = 1; } if (dev_id >= 0 && dev_id < (DAVINCI_EDMA_NUM_DMACH)) { /* The 64 Channels are mapped to the first 64 PARAM entries */ if (!dma_chan[dev_id].in_use) { *lch = dev_id; dma_chan[*lch].param_no = request_param(*lch, dev_id); if (dma_chan[*lch].param_no == -1) { return -EINVAL; } else dev_dbg(&edma_dev.dev, "param_no=%d\r\n", dma_chan[*lch].param_no); if (callback) { dma_chan[*lch].tcc = request_dma_interrupt(*lch, callback, data, dma_chan[*lch]. param_no, *tcc); if (dma_chan[*lch].tcc == -1) { return -EINVAL; } else { *tcc = dma_chan[*lch].tcc; dev_dbg(&edma_dev.dev, "tcc_no=%d\r\n", dma_chan[*lch].tcc); } } else dma_chan[*lch].tcc = -1; map_dmach_queue(dev_id, eventq_no); ret_val = 0; } else ret_val = -EINVAL; } else if (dev_id >= DAVINCI_EDMA_NUM_DMACH && dev_id < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { if ((qdam_to_param_mapping[dev_id - DAVINCI_EDMA_NUM_DMACH] != -1) && (dma_chan [qdam_to_param_mapping[dev_id - DAVINCI_EDMA_NUM_DMACH]]. in_use) ) { ret_val = -EINVAL; } else { *lch = dev_id; dma_chan[*lch].param_no = request_param(*lch, dev_id); if (dma_chan[*lch].param_no == -1) { dev_dbg(&edma_dev.dev, "request_param failed\r\n"); return -EINVAL; } else { dev_dbg(&edma_dev.dev, "param_no=%d\r\n", dma_chan[*lch].param_no); map_dmach_param(*lch, dma_chan[*lch].param_no); } if (callback) { dma_chan[*lch].tcc = request_dma_interrupt(*lch, callback, data, dma_chan[*lch]. param_no, *tcc); if (dma_chan[*lch].tcc == -1) { return -EINVAL; } else { *tcc = dma_chan[*lch].tcc; dev_dbg(&edma_dev.dev, "tcc_no=%d\r\n", dma_chan[*lch].tcc); } } else dma_chan[*lch].tcc = -1; map_dmach_queue(dev_id, eventq_no); ret_val = 0; } } else if (dev_id == DAVINCI_DMA_CHANNEL_ANY) { i = 0; ret_val = 0; while (dma_chan_no_event[i] != -1) { if (!dma_chan[dma_chan_no_event[i]].in_use) { *lch = dma_chan_no_event[i]; dma_chan[*lch].param_no = request_param(*lch, dev_id); if (dma_chan[*lch].param_no == -1) { return -EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -