| /* Wrapper for DMA channel allocator that starts clocks etc */ |
| |
| #include <linux/kernel.h> |
| #include <linux/spinlock.h> |
| #include <asm/dma.h> |
| #include <hwregs/reg_map.h> |
| #include <hwregs/reg_rdwr.h> |
| #include <hwregs/marb_defs.h> |
| #include <hwregs/config_defs.h> |
| #include <hwregs/strmux_defs.h> |
| #include <linux/errno.h> |
| #include <mach/arbiter.h> |
| |
| static char used_dma_channels[MAX_DMA_CHANNELS]; |
| static const char *used_dma_channels_users[MAX_DMA_CHANNELS]; |
| |
| static DEFINE_SPINLOCK(dma_lock); |
| |
| int crisv32_request_dma(unsigned int dmanr, const char *device_id, |
| unsigned options, unsigned int bandwidth, |
| enum dma_owner owner) |
| { |
| unsigned long flags; |
| reg_config_rw_clk_ctrl clk_ctrl; |
| reg_strmux_rw_cfg strmux_cfg; |
| |
| if (crisv32_arbiter_allocate_bandwidth(dmanr, |
| options & DMA_INT_MEM ? |
| INT_REGION : EXT_REGION, |
| bandwidth)) |
| return -ENOMEM; |
| |
| spin_lock_irqsave(&dma_lock, flags); |
| |
| if (used_dma_channels[dmanr]) { |
| spin_unlock_irqrestore(&dma_lock, flags); |
| if (options & DMA_VERBOSE_ON_ERROR) { |
| printk(KERN_ERR "Failed to request DMA %i for %s, " |
| "already allocated by %s\n", |
| dmanr, |
| device_id, |
| used_dma_channels_users[dmanr]); |
| } |
| if (options & DMA_PANIC_ON_ERROR) |
| panic("request_dma error!"); |
| return -EBUSY; |
| } |
| clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); |
| strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg); |
| |
| switch (dmanr) { |
| case 0: |
| case 1: |
| clk_ctrl.dma01_eth0 = 1; |
| break; |
| case 2: |
| case 3: |
| clk_ctrl.dma23 = 1; |
| break; |
| case 4: |
| case 5: |
| clk_ctrl.dma45 = 1; |
| break; |
| case 6: |
| case 7: |
| clk_ctrl.dma67 = 1; |
| break; |
| case 8: |
| case 9: |
| clk_ctrl.dma89_strcop = 1; |
| break; |
| #if MAX_DMA_CHANNELS-1 != 9 |
| #error Check dma.c |
| #endif |
| default: |
| spin_unlock_irqrestore(&dma_lock, flags); |
| if (options & DMA_VERBOSE_ON_ERROR) { |
| printk(KERN_ERR "Failed to request DMA %i for %s, " |
| "only 0-%i valid)\n", |
| dmanr, device_id, MAX_DMA_CHANNELS - 1); |
| } |
| |
| if (options & DMA_PANIC_ON_ERROR) |
| panic("request_dma error!"); |
| return -EINVAL; |
| } |
| |
| switch (owner) { |
| case dma_eth0: |
| if (dmanr == 0) |
| strmux_cfg.dma0 = regk_strmux_eth0; |
| else if (dmanr == 1) |
| strmux_cfg.dma1 = regk_strmux_eth0; |
| else |
| panic("Invalid DMA channel for eth0\n"); |
| break; |
| case dma_eth1: |
| if (dmanr == 6) |
| strmux_cfg.dma6 = regk_strmux_eth1; |
| else if (dmanr == 7) |
| strmux_cfg.dma7 = regk_strmux_eth1; |
| else |
| panic("Invalid DMA channel for eth1\n"); |
| break; |
| case dma_iop0: |
| if (dmanr == 2) |
| strmux_cfg.dma2 = regk_strmux_iop0; |
| else if (dmanr == 3) |
| strmux_cfg.dma3 = regk_strmux_iop0; |
| else |
| panic("Invalid DMA channel for iop0\n"); |
| break; |
| case dma_iop1: |
| if (dmanr == 4) |
| strmux_cfg.dma4 = regk_strmux_iop1; |
| else if (dmanr == 5) |
| strmux_cfg.dma5 = regk_strmux_iop1; |
| else |
| panic("Invalid DMA channel for iop1\n"); |
| break; |
| case dma_ser0: |
| if (dmanr == 6) |
| strmux_cfg.dma6 = regk_strmux_ser0; |
| else if (dmanr == 7) |
| strmux_cfg.dma7 = regk_strmux_ser0; |
| else |
| panic("Invalid DMA channel for ser0\n"); |
| break; |
| case dma_ser1: |
| if (dmanr == 4) |
| strmux_cfg.dma4 = regk_strmux_ser1; |
| else if (dmanr == 5) |
| strmux_cfg.dma5 = regk_strmux_ser1; |
| else |
| panic("Invalid DMA channel for ser1\n"); |
| break; |
| case dma_ser2: |
| if (dmanr == 2) |
| strmux_cfg.dma2 = regk_strmux_ser2; |
| else if (dmanr == 3) |
| strmux_cfg.dma3 = regk_strmux_ser2; |
| else |
| panic("Invalid DMA channel for ser2\n"); |
| break; |
| case dma_ser3: |
| if (dmanr == 8) |
| strmux_cfg.dma8 = regk_strmux_ser3; |
| else if (dmanr == 9) |
| strmux_cfg.dma9 = regk_strmux_ser3; |
| else |
| panic("Invalid DMA channel for ser3\n"); |
| break; |
| case dma_sser0: |
| if (dmanr == 4) |
| strmux_cfg.dma4 = regk_strmux_sser0; |
| else if (dmanr == 5) |
| strmux_cfg.dma5 = regk_strmux_sser0; |
| else |
| panic("Invalid DMA channel for sser0\n"); |
| break; |
| case dma_sser1: |
| if (dmanr == 6) |
| strmux_cfg.dma6 = regk_strmux_sser1; |
| else if (dmanr == 7) |
| strmux_cfg.dma7 = regk_strmux_sser1; |
| else |
| panic("Invalid DMA channel for sser1\n"); |
| break; |
| case dma_ata: |
| if (dmanr == 2) |
| strmux_cfg.dma2 = regk_strmux_ata; |
| else if (dmanr == 3) |
| strmux_cfg.dma3 = regk_strmux_ata; |
| else |
| panic("Invalid DMA channel for ata\n"); |
| break; |
| case dma_strp: |
| if (dmanr == 8) |
| strmux_cfg.dma8 = regk_strmux_strcop; |
| else if (dmanr == 9) |
| strmux_cfg.dma9 = regk_strmux_strcop; |
| else |
| panic("Invalid DMA channel for strp\n"); |
| break; |
| case dma_ext0: |
| if (dmanr == 6) |
| strmux_cfg.dma6 = regk_strmux_ext0; |
| else |
| panic("Invalid DMA channel for ext0\n"); |
| break; |
| case dma_ext1: |
| if (dmanr == 7) |
| strmux_cfg.dma7 = regk_strmux_ext1; |
| else |
| panic("Invalid DMA channel for ext1\n"); |
| break; |
| case dma_ext2: |
| if (dmanr == 2) |
| strmux_cfg.dma2 = regk_strmux_ext2; |
| else if (dmanr == 8) |
| strmux_cfg.dma8 = regk_strmux_ext2; |
| else |
| panic("Invalid DMA channel for ext2\n"); |
| break; |
| case dma_ext3: |
| if (dmanr == 3) |
| strmux_cfg.dma3 = regk_strmux_ext3; |
| else if (dmanr == 9) |
| strmux_cfg.dma9 = regk_strmux_ext2; |
| else |
| panic("Invalid DMA channel for ext2\n"); |
| break; |
| } |
| |
| used_dma_channels[dmanr] = 1; |
| used_dma_channels_users[dmanr] = device_id; |
| REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl); |
| REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg); |
| spin_unlock_irqrestore(&dma_lock, flags); |
| return 0; |
| } |
| |
| void crisv32_free_dma(unsigned int dmanr) |
| { |
| spin_lock(&dma_lock); |
| used_dma_channels[dmanr] = 0; |
| spin_unlock(&dma_lock); |
| } |