📄 dma-omap24xx.c
字号:
} return IRQ_HANDLED;}/* enable interrupts for this channel*/void omap_enable_irq_lch(int lch){ u32 w; w = readl(OMAP_DMA4_IRQENABLE_L0); w |= 1 << lch; writel(w, OMAP_DMA4_IRQENABLE_L0);}int omap_request_dma(int dev_id, const char *dev_name, void (*callback) (int lch, u16 ch_status, void *data), void *data, int *dma_ch_out){ int ch, free_ch = -1; unsigned long flags; spin_lock_irqsave(&dma_chan_lock, flags); for (ch = 0; ch < dma_chan_count; ch++) { if (free_ch == -1 && dma_chan[ch].dev_id == -1 && dma_chan[ch].reserved == -1) { free_ch = ch; if (dev_id == 0) break; } /* if (dev_id != 0 && dma_chan[ch].dev_id == dev_id) { spin_unlock_irqrestore(&dma_chan_lock, flags); return -EAGAIN; } */ } if (free_ch == -1) { spin_unlock_irqrestore(&dma_chan_lock, flags); return -EBUSY; } dma_chan[free_ch].dev_id = dev_id; dma_chan[free_ch].reserved = 1; clear_lch_regs(free_ch); spin_unlock_irqrestore(&dma_chan_lock, flags); dma_chan[free_ch].dev_name = dev_name; dma_chan[free_ch].callback = callback; dma_chan[free_ch].data = data; dma_chan[free_ch].enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ; omap_enable_irq_lch(free_ch); omap_enable_dma_irq(free_ch); /* clear the CSR register and IRQ status register */ writel(0x0, OMAP_DMA4_CSR_REG(free_ch)); writel(~0x0, OMAP_DMA4_IRQSTATUS_L0); *dma_ch_out = free_ch; return 0;}int omap_request_dma_chain(int dev_id, const char *dev_name, int num_transfers, /* if num_transfer > 1 ... chaining logic will be used */ void (*callback) (int lch, u16 ch_status, void *data), void *data, int *dma_ch_out, lch_chain ** chain){ int ch; unsigned long flags; u8 chan_allocated = 0; int firstch = -1; int lastch = 0; int i; local_irq_save(flags); /* trying to allocate logical channels from the pool */ for (ch = 0; ch < dma_chan_count; ch++) { if (dma_chan[ch].dev_id == -1 && dma_chan[ch].reserved == -1) { dma_chan[ch].reserved = 1; chan_allocated++; if (firstch == -1) firstch = ch; else dma_chan[lastch].next_channel = ch; lastch = ch; } if (chan_allocated >= num_transfers) break; } dma_chan[ch].next_channel = firstch; /* num channels requested less than the free channels in the pool */ if (chan_allocated < num_transfers) { for (ch = 0; ch < dma_chan_count; ch++) { if (dma_chan[ch].dev_id == dev_id) { dma_chan[ch].dev_id = -1; dma_chan[ch].reserved = -1; } } local_irq_restore(flags); return -EBUSY; } *chain = kmalloc(sizeof(lch_chain), GFP_KERNEL); if (chain == NULL) return -ENOMEM; (*chain)->queue_head = firstch; (*chain)->queue_tail = firstch; (*chain)->num_channels = num_transfers; (*chain)->started = 0; (*chain)->queued = 0; /* logical channels allocated , initialize the channels */ ch = firstch; for (i = 0; i < num_transfers; i++) { dma_chan[ch].dev_id = dev_id; dma_chan[ch].callback = callback; dma_chan[ch].data = data; dma_chan[ch].dev_name = dev_name; dma_chan[ch].params_set = 0; dma_chan[ch].mychain = *chain; clear_lch_regs(ch); setup_chain(ch, dma_chan[ch].next_channel); /* enable interrupts for this channel */ omap_enable_irq_lch(ch); dma_chan[ch].enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ; /* enable some nice interrupts */ /* enable DROP event and End of Block */ omap_enable_dma_irq(ch); /* clear the CSR register and IRQ status register */ writel(0x0, OMAP_DMA4_CSR_REG(ch)); writel(~0x0, OMAP_DMA4_IRQSTATUS_L0); ch = dma_chan[ch].next_channel; /* one common ISR for all the channels is inserted upfront in the init routine */ } local_irq_restore(flags); *dma_ch_out = firstch; return 0;}void omap_free_dma(int lch){ u32 w; if (dma_chan[lch].reserved == -1) { printk(KERN_INFO "omap_dma: trying to free nonallocated DMA channel %d\n", lch); return; } dma_chan[lch].reserved = -1; dma_chan[lch].dev_id = -1; dma_chan[lch].callback = NULL; /* disable interrupts */ w = readl(OMAP_DMA4_IRQENABLE_L0); w &= ~(1 << lch); writel(w, OMAP_DMA4_IRQENABLE_L0); /* clear the CSR register and IRQ status register */ writel(0x0, OMAP_DMA4_CSR_REG(lch)); w = readl(OMAP_DMA4_IRQSTATUS_L0); w |= 1 << lch; writel(w, OMAP_DMA4_IRQSTATUS_L0); /* Disable all DMA interrupts for the channel. */ writel(0, OMAP_DMA4_CICR_REG(lch)); /* Make sure the DMA transfer is stopped. */ writel(0, OMAP_DMA4_CCR_REG(lch)); clear_lch_regs(lch);}void omap_free_dma_chain(lch_chain * chain){ int i; int ch = chain->queue_head; int num_ch = chain->num_channels; int lch = ch; for (i = 0; i < num_ch; i++) { ch = lch; omap_free_dma(lch); lch = dma_chan[lch].next_channel; dma_chan[ch].next_channel = 0; } kfree(chain); return;}void omap_clear_dma_chain(lch_chain * chain){ int i; int ch = chain->queue_head; int num_ch = chain->num_channels; int lch = ch; for (i = 0; i < num_ch; i++) { clear_lch_regs(lch); lch = dma_chan[lch].next_channel; } return;}static struct irqaction omap24xx_dma4_irq = { .name = "OMAP24XX DMA IRQ demux", .handler = omap24xx_dma4_irq_demux, .flags = SA_INTERRUPT};int __init omap_init_dma(void){ int ch; printk(KERN_INFO "OMAP DMA4 hardware Initialized "); dma_chan_count = OMAP24XX_LOGICAL_DMA_CH_COUNT; memset(&dma_chan, 0, sizeof(dma_chan)); spin_lock_init(&dma_chan_lock); for (ch = 0; ch < dma_chan_count; ch++) { clear_lch_regs(ch); dma_chan[ch].reserved = -1; dma_chan[ch].dev_id = -1; } /* register the ISR */ /* for 24xx we register a common ISR and then demuxing will be done inside the ISR */ setup_irq(INT_SDMA_IRQ0, &omap24xx_dma4_irq);#ifdef DMA_TEST /*test */ dma_24xx_framework_test();#endif return 0;}#ifdef DMA_TESTint dma_24xx_framework_test(){#define dev_name "dummy dev" lch_chain *chain; int dev_id = 1234; //dummy int dma_ch, ch1, ch2, ch3; int ret; int dummy_private_data; int *buf1, *buf2, *buf3, *buf4; int buf1_phys, buf2_phys; dma_channel_params params; buf1 = kmalloc(30000, GFP_KERNEL); buf2 = kmalloc(30000, GFP_KERNEL); buf1_phys = __virt_to_phys((int)buf1); buf2_phys = __virt_to_phys((int)buf2); printk(KERN_INFO "\n buf1 = %x, buf2 = %x buf1_phys = %x buf2_phys = %x", buf1, buf2, buf1_phys, buf2_phys);/* simple chained dma transfer */#if 0 printk("\n simple dma chained transfer test "); ret = omap_request_dma(dev_id, dev_name, NULL, &dummy_private_data, &ch1); ret = omap_request_dma(dev_id, dev_name, NULL, &dummy_private_data, &ch2); ret = omap_request_dma(dev_id, dev_name, NULL, &dummy_private_data, &ch3); printk("\n dma channel allocated ch1= %d, ch2 = %d, ch3 = %d", ch1, ch2, ch3); params.data_type = 0x1; /* data type 16 */ params.elem_count = 1000; params.frame_count = 1; params.src_amode = 1; /* post increment */ params.src_start = buf1_phys; params.src_ei = 0; params.src_fi = 0; params.dst_amode = 1; params.dst_start = buf2_phys; /* source address : physical */ params.dst_ei = 0; params.dst_fi = 0; /* source frame index */ params.trigger = 0; params.sync_mode = 0; params.src_or_dst_synch = 0; omap_set_dma_params(ch1, params); params.src_start = buf1_phys + 1000; params.dst_start = buf2_phys + 1000; omap_set_dma_params(ch2, params); params.src_start = buf1_phys + 2000; params.dst_start = buf2_phys + 2000; omap_set_dma_params(ch3, params); setup_chain(ch1, ch2); enable_chain(ch1, ch2); setup_chain(ch2, ch3); enable_chain(ch2, ch3); omap_start_dma(ch1); //printk(KERN_INFO "\n dma channel started waiting for interrupt");#endif/* simple dma transfer */#if 1 printk("\n simple dma transfer test"); ret = omap_request_dma(dev_id, dev_name, NULL, &dummy_private_data, &dma_ch); printk("\n dma channel allocated = %d", dma_ch); params.data_type = 0x1; /* data type 16 */ params.elem_count = 4096; params.frame_count = 1; params.src_amode = 1; /* post increment */ params.src_start = buf1_phys; params.src_ei = 0; params.src_fi = 0; params.dst_amode = 1; params.dst_start = buf2_phys; /* source address : physical */ params.dst_ei = 0; params.dst_fi = 0; /* source frame index */ params.trigger = 0; params.sync_mode = 0; params.src_or_dst_synch = 0; omap_set_dma_params(dma_ch, params); omap_start_dma(dma_ch); printk(KERN_INFO "\n dma channel started waiting for interrupt");#endif#if 0 printk("\n queued chained dma transfer test"); ret = omap_request_dma_chain(dev_id, dev_name, 3, NULL, &dummy_private_data, &dma_ch, &chain); printk("\n dma channel allocated chained= %d", dma_ch); params.data_type = 0x1; /* data type 16 */ params.elem_count = 10000; params.frame_count = 1; params.src_amode = 1; /* post increment */ params.src_start = buf1_phys; params.src_ei = 0; params.src_fi = 0; params.dst_amode = 1; params.dst_start = buf2_phys; /* source address : physical */ params.dst_ei = 0; params.dst_fi = 0; /* source frame index */ params.trigger = 0; params.sync_mode = 0; params.src_or_dst_synch = 0; ret = omap_set_dma_params_chain(chain, params); ret = omap_start_dma_chain(chain); params.src_start = buf1_phys + 10000; params.dst_start = buf2_phys + 10000; ret = omap_set_dma_params_chain(chain, params); ret = omap_start_dma_chain(chain); params.src_start = buf1_phys + 20000; params.dst_start = buf2_phys + 20000; ret = omap_set_dma_params_chain(chain, params); ret = omap_start_dma_chain(chain);#endif kfree(buf1); kfree(buf2); return 0;}#endif//#endif__initcall(omap_init_dma);EXPORT_SYMBOL(omap_request_dma);EXPORT_SYMBOL(omap_free_dma);EXPORT_SYMBOL(omap_start_dma);EXPORT_SYMBOL(omap_stop_dma);EXPORT_SYMBOL(omap_set_dma_transfer_params);EXPORT_SYMBOL(omap_set_dma_src_params);EXPORT_SYMBOL(omap_set_dma_dest_params);EXPORT_SYMBOL(omap_set_dma_params);EXPORT_SYMBOL(omap_get_dma_pos_src);EXPORT_SYMBOL(omap_get_dma_pos_dst);EXPORT_SYMBOL(omap_request_dma_chain);EXPORT_SYMBOL(omap_free_dma_chain);EXPORT_SYMBOL(omap_start_dma_chain);EXPORT_SYMBOL(omap_stop_dma_chain);EXPORT_SYMBOL(omap_set_dma_params_chain);EXPORT_SYMBOL(omap_clear_dma_chain);EXPORT_SYMBOL(omap_disable_dma_irq);EXPORT_SYMBOL(disable_chain);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -