📄 dma.c
字号:
dev_dbg(&edma_dev.dev, "ER=%d\r\n", ptr_edmacc_regs->shadow[0].er); /* Clear any pedning error */ (lch < 32) ? (ptr_edmacc_regs->emcr |= (1UL << lch)) : (ptr_edmacc_regs->emcrh |= (1UL << (lch - 32))); /* Clear any SER */ (lch < 32) ? (ptr_edmacc_regs->shadow[0].secr |= (1UL << lch)) : (ptr_edmacc_regs->shadow[0].secrh |= (1UL << (lch - 32))); (lch < 32) ? (ptr_edmacc_regs->shadow[0].eesr |= (1UL << lch)) : (ptr_edmacc_regs->shadow[0].eesrh |= (1UL << (lch - 32))); dev_dbg(&edma_dev.dev, "EER=%d\r\n", ptr_edmacc_regs->shadow[0].eer); ret_val = 0; } } else if ((lch >= DAVINCI_EDMA_NUM_DMACH) && (lch < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH))) { ptr_edmacc_regs->shadow[0].qeesr |= (1 << (lch - DAVINCI_EDMA_NUM_DMACH)); ret_val = 0; } else { /* for slaveChannels */ ret_val = EINVAL; } return ret_val;}/****************************************************************************** * * DMA Stop - Stops the dma on the channel passed * ARGUMENTS: * lch - logical channel number * *****************************************************************************/void davinci_stop_dma(int lch){ if (lch < DAVINCI_EDMA_NUM_DMACH) { int flag = 0; int i = 0; /* If the dma stop request is for the unused events */ while (dma_chan_no_event[i] != -1) { if (dma_chan_no_event[i] == lch) { /* EDMA channels without event association */ /* if the requested channel is one of the unused channels then reset the coresponding bit of ESR-Event Set Register */ flag = 1; break; } i++; } if (!flag) { /* EDMA channel with event association */ (lch < 32) ? (ptr_edmacc_regs->shadow[0].eecr |= (1UL << lch)) : (ptr_edmacc_regs->shadow[0].eecrh |= (1UL << (lch - 32))); if (lch < 32) { if (ptr_edmacc_regs->shadow[0].er & (1 << lch)) { dev_dbg(&edma_dev.dev, "ER=%x\n", ptr_edmacc_regs->shadow[0].er); ptr_edmacc_regs->shadow[0].ecr |= (1 << lch); } } else { if (ptr_edmacc_regs->shadow[0].erh & (1 << (lch - 32))) { dev_dbg(&edma_dev.dev, "ERH=%x\n", ptr_edmacc_regs->shadow[0].erh); ptr_edmacc_regs->shadow[0].ecrh |= (1 << (lch - 32)); } } if (lch < 32) { if (ptr_edmacc_regs->shadow[0].ser & (1 << lch)) { dev_dbg(&edma_dev.dev, "SER=%x\n", ptr_edmacc_regs->shadow[0].ser); ptr_edmacc_regs->shadow[0].secr |= (1 << lch); } else { } } else { if (ptr_edmacc_regs-> shadow[0].serh & (1 << (lch - 32))) { dev_dbg(&edma_dev.dev, "SERH=%x\n", ptr_edmacc_regs->shadow[0]. serh); ptr_edmacc_regs->shadow[0].secrh |= (1 << (lch - 32)); } } if (lch < 32) { if (ptr_edmacc_regs->emr & (1 << lch)) { dev_dbg(&edma_dev.dev, "EMR=%x\n", ptr_edmacc_regs->emr); ptr_edmacc_regs->emcr |= (1 << lch); } } else { if (ptr_edmacc_regs->emrh & (1 << (lch - 32))) { dev_dbg(&edma_dev.dev, "EMRH=%x\n", ptr_edmacc_regs->emrh); ptr_edmacc_regs->emcrh |= (1 << (lch - 32)); } } dev_dbg(&edma_dev.dev, "EER=%d\r\n", ptr_edmacc_regs->shadow[0].eer); /* if the requested channel is one of the event channels then just set the link field of the corresponding param entry to 0xffff */ } } else if ((lch >= DAVINCI_EDMA_NUM_DMACH) && (lch < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH))) { /* for QDMA channels */ ptr_edmacc_regs->qeecr |= (1 << (lch - DAVINCI_EDMA_NUM_DMACH)); dev_dbg(&edma_dev.dev, "QER=%d\r\n", ptr_edmacc_regs->qer); dev_dbg(&edma_dev.dev, "QEER=%d\r\n", ptr_edmacc_regs->qeer); } else if ((lch >= (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) && lch < DAVINCI_EDMA_NUM_PARAMENTRY) { /* for slaveChannels */ ptr_edmacc_regs->paramentry[lch].link_bcntrld &= 0xffff0000; ptr_edmacc_regs->paramentry[lch].link_bcntrld |= 0xffff; } else { }}/****************************************************************************** * * 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){ unsigned long link; int temp_ch = 0; if (lch_head >= DAVINCI_EDMA_NUM_DMACH && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { temp_ch = qdam_to_param_mapping[lch_head - DAVINCI_EDMA_NUM_DMACH]; lch_head = temp_ch; } if (lch_queue >= DAVINCI_EDMA_NUM_DMACH && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { temp_ch = qdam_to_param_mapping[lch_queue - DAVINCI_EDMA_NUM_DMACH]; lch_queue = temp_ch; } if ((lch_head >= 0 && lch_head < DAVINCI_EDMA_NUM_PARAMENTRY) && (lch_queue >= 0 && lch_queue < DAVINCI_EDMA_NUM_PARAMENTRY)) { /* program LINK */ link = (unsigned long)(& (ptr_edmacc_regs-> paramentry[dma_chan[lch_queue].param_no].opt)); ptr_edmacc_regs-> paramentry[dma_chan [lch_head].param_no].link_bcntrld &= 0xffff0000; ptr_edmacc_regs-> paramentry[dma_chan [lch_head]. param_no].link_bcntrld |= ((unsigned short) link); dma_chan[lch_head].link_lch = lch_queue; }}/****************************************************************************** * * 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){ int temp_ch = 0; if (lch_head >= DAVINCI_EDMA_NUM_DMACH && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { temp_ch = qdam_to_param_mapping[lch_head - DAVINCI_EDMA_NUM_DMACH]; lch_head = temp_ch; } if (lch_queue >= DAVINCI_EDMA_NUM_DMACH && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { temp_ch = qdam_to_param_mapping[lch_queue - DAVINCI_EDMA_NUM_DMACH]; lch_queue = temp_ch; } if ((lch_head >= 0 && lch_head < DAVINCI_EDMA_NUM_PARAMENTRY) && (lch_queue >= 0 && lch_queue < DAVINCI_EDMA_NUM_PARAMENTRY)) { ptr_edmacc_regs-> paramentry[dma_chan [lch_head].param_no].link_bcntrld |= 0xffff; dma_chan[lch_head].link_lch = -1; }}/****************************************************************************** * * DMA channel chain - chains the two logical channels passed through by * 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_chain_lch(int lch_head, int lch_queue){ int temp_ch = 0; if (lch_head >= DAVINCI_EDMA_NUM_DMACH && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { temp_ch = qdam_to_param_mapping[lch_head - DAVINCI_EDMA_NUM_DMACH]; lch_head = temp_ch; } if (lch_queue >= DAVINCI_EDMA_NUM_DMACH && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { temp_ch = qdam_to_param_mapping[lch_queue - DAVINCI_EDMA_NUM_DMACH]; lch_queue = temp_ch; } if ((lch_head >= 0 && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) && (lch_queue >= 0 && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) ) { /* set TCCHEN */ /* set TCCHEN */ ptr_edmacc_regs->paramentry[lch_head].opt |= TCCHEN; /* program tcc */ ptr_edmacc_regs->paramentry[lch_head].opt &= (~TCC); ptr_edmacc_regs-> paramentry[lch_head].opt |= (lch_queue & 0x3f) << 12; }}/****************************************************************************** * * DMA channel unchain - unchain the two logical channels passed through by * 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_unchain_lch(int lch_head, int lch_queue){ int temp_ch = 0; if (lch_head >= DAVINCI_EDMA_NUM_DMACH && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { temp_ch = qdam_to_param_mapping[lch_head - DAVINCI_EDMA_NUM_DMACH]; lch_head = temp_ch; } if (lch_queue >= DAVINCI_EDMA_NUM_DMACH && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) { temp_ch = qdam_to_param_mapping[lch_queue - DAVINCI_EDMA_NUM_DMACH]; lch_queue = temp_ch; } if ((lch_head >= 0 && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) && (lch_queue >= 0 && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH))) { /* reset TCCHEN */ ptr_edmacc_regs->paramentry[lch_head].opt &= ~TCCHEN; }}/****************************************************************************** * * It cleans ParamEntry qand bring back EDMA to initial state if media has * been removed before EDMA has finished.It is usedful for removable media. * Arguments: * ch_no - channel no * * Return: zero on success, or corresponding error no on failure * *****************************************************************************/void davinci_clean_channel(int ch_no){ int i; dev_dbg(&edma_dev.dev, "EMR =%d\r\n", ptr_edmacc_regs->emr); if (ch_no < 32) { for (i = 0; i < 32; i++) { if (ch_no == i) { ptr_edmacc_regs->shadow[0].ecr |= (1 << i); /* Clear the corresponding EMR bits */ ptr_edmacc_regs->emcr |= (1 << i); /* Clear any SER */ ptr_edmacc_regs->shadow[0].secr |= (1 << i); ptr_edmacc_regs->ccerrclr |= ((1 << 16) | 0x3); } } } if (ch_no > 32) { dev_dbg(&edma_dev.dev, "EMRH =%d\r\n", ptr_edmacc_regs->emrh); for (i = 0; i < 32; i++) { if (ch_no == (i + 32)) { ptr_edmacc_regs->shadow[0].ecrh |= (1 << i); /* Clear the corresponding IPR bits */ ptr_edmacc_regs->emcrh |= (1 << i); /* Clear any SER */ ptr_edmacc_regs->shadow[0].secrh |= (1 << i); ptr_edmacc_regs->ccerrclr |= ((1 << 16) | 0x3); } } }}/****************************************************************************** * * DMA interrupt handlers * *****************************************************************************/static int dma_irq_handler_l(int sound_curr_lch, void *ch_status, struct pt_regs *data){ dev_dbg(&edma_dev.dev, "dma_irq_handler\n"); (*cb[0]) (); return IRQ_HANDLED;}static int dma_ccerr_handler_l (int sound_curr_lch, void *ch_status, struct pt_regs *data) { dev_dbg(&edma_dev.dev, "dma_ccerr_handler\n"); (*cb[1]) (); return IRQ_HANDLED;}static int dma_tc1err_handler_l (int sound_curr_lch, void *ch_status, struct pt_regs *data) { dev_dbg(&edma_dev.dev, "dma_tc1err_handler\n"); (*cb[2]) (); return IRQ_HANDLED;}static int dma_tc2err_handler_l (int sound_curr_lch, void *ch_status, struct pt_regs *data) { dev_dbg(&edma_dev.dev, "dma_tc2err_handler\n"); (*cb[3]) (); return IRQ_HANDLED;}int register_dma_interrupts (intr_callback cb1, intr_callback cb2, intr_callback cb3, intr_callback cb4) { cb[0] = cb1; cb[1] = cb2; cb[2] = cb3; cb[3] = cb4; if (!cb1 || !cb2 || !cb3 || !cb4) { dev_dbg(&edma_dev.dev, "NULL callback\n"); return -1; } if (request_irq(IRQ_CCINT0, dma_irq_handler_l, 0, "EDMA", NULL)) { dev_dbg(&edma_dev.dev, "request_irq failed\n"); return -1; } if (request_irq (IRQ_CCERRINT, dma_ccerr_handler_l, 0, "EDMA CC Err", NULL)) { dev_dbg(&edma_dev.dev, "request_irq failed\n"); return -1; } if (request_irq (IRQ_TCERRINT0, dma_tc1err_handler_l, 0, "EDMA TC1 Err", NULL)) { dev_dbg(&edma_dev.dev, "request_irq failed\n"); return -1; } if (request_irq (IRQ_TCERRINT, dma_tc2err_handler_l, 0, "EDMA TC2 Err", NULL)) { dev_dbg(&edma_dev.dev, "request_irq failed\n"); return -1; } return 0;}arch_initcall(arch_dma_init);EXPORT_SYMBOL(davinci_start_dma);EXPORT_SYMBOL(davinci_dma_link_lch);EXPORT_SYMBOL(davinci_set_dma_params);EXPORT_SYMBOL(davinci_get_dma_params);EXPORT_SYMBOL(davinci_set_dma_transfer_params);EXPORT_SYMBOL(davinci_set_dma_dest_index);EXPORT_SYMBOL(davinci_set_dma_src_index);EXPORT_SYMBOL(davinci_set_dma_dest_params);EXPORT_SYMBOL(davinci_set_dma_src_params);EXPORT_SYMBOL(davinci_request_dma);EXPORT_SYMBOL(davinci_stop_dma);EXPORT_SYMBOL(davinci_clean_channel);EXPORT_SYMBOL(davinci_free_dma);EXPORT_SYMBOL(davinci_dma_chain_lch);EXPORT_SYMBOL(davinci_dma_unchain_lch);EXPORT_SYMBOL(davinci_dma_unlink_lch);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -