2007-11-30 00:11:23 +08:00
|
|
|
/* Wrapper for DMA channel allocator that starts clocks etc */
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/spinlock.h>
|
2008-10-21 23:45:58 +08:00
|
|
|
#include <mach/dma.h>
|
2007-11-30 00:11:23 +08:00
|
|
|
#include <hwregs/reg_map.h>
|
|
|
|
#include <hwregs/reg_rdwr.h>
|
|
|
|
#include <hwregs/marb_defs.h>
|
|
|
|
#include <hwregs/clkgen_defs.h>
|
|
|
|
#include <hwregs/strmux_defs.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <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_clkgen_rw_clk_ctrl clk_ctrl;
|
|
|
|
reg_strmux_rw_cfg strmux_cfg;
|
|
|
|
|
2008-02-08 17:44:05 +08:00
|
|
|
if (crisv32_arbiter_allocate_bandwidth(dmanr,
|
2007-11-30 00:11:23 +08:00
|
|
|
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!");
|
|
|
|
spin_unlock_irqrestore(&dma_lock, flags);
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
|
|
|
|
strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg);
|
|
|
|
|
|
|
|
switch (dmanr) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
clk_ctrl.dma0_1_eth = 1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
|
|
clk_ctrl.dma2_3_strcop = 1;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
clk_ctrl.dma4_5_iop = 1;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
case 7:
|
|
|
|
clk_ctrl.sser_ser_dma6_7 = 1;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
case 11:
|
|
|
|
clk_ctrl.dma9_11 = 1;
|
|
|
|
break;
|
|
|
|
#if MAX_DMA_CHANNELS-1 != 11
|
|
|
|
#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_eth:
|
|
|
|
if (dmanr == 0)
|
|
|
|
strmux_cfg.dma0 = regk_strmux_eth;
|
|
|
|
else if (dmanr == 1)
|
|
|
|
strmux_cfg.dma1 = regk_strmux_eth;
|
|
|
|
else
|
|
|
|
panic("Invalid DMA channel for eth\n");
|
|
|
|
break;
|
|
|
|
case dma_ser0:
|
|
|
|
if (dmanr == 0)
|
|
|
|
strmux_cfg.dma0 = regk_strmux_ser0;
|
|
|
|
else if (dmanr == 1)
|
|
|
|
strmux_cfg.dma1 = regk_strmux_ser0;
|
|
|
|
else
|
|
|
|
panic("Invalid DMA channel for ser0\n");
|
|
|
|
break;
|
|
|
|
case dma_ser3:
|
|
|
|
if (dmanr == 2)
|
|
|
|
strmux_cfg.dma2 = regk_strmux_ser3;
|
|
|
|
else if (dmanr == 3)
|
|
|
|
strmux_cfg.dma3 = regk_strmux_ser3;
|
|
|
|
else
|
|
|
|
panic("Invalid DMA channel for ser3\n");
|
|
|
|
break;
|
|
|
|
case dma_strp:
|
|
|
|
if (dmanr == 2)
|
|
|
|
strmux_cfg.dma2 = regk_strmux_strcop;
|
|
|
|
else if (dmanr == 3)
|
|
|
|
strmux_cfg.dma3 = regk_strmux_strcop;
|
|
|
|
else
|
|
|
|
panic("Invalid DMA channel for strp\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_iop:
|
|
|
|
if (dmanr == 4)
|
|
|
|
strmux_cfg.dma4 = regk_strmux_iop;
|
|
|
|
else if (dmanr == 5)
|
|
|
|
strmux_cfg.dma5 = regk_strmux_iop;
|
|
|
|
else
|
|
|
|
panic("Invalid DMA channel for iop\n");
|
|
|
|
break;
|
|
|
|
case dma_ser2:
|
|
|
|
if (dmanr == 6)
|
|
|
|
strmux_cfg.dma6 = regk_strmux_ser2;
|
|
|
|
else if (dmanr == 7)
|
|
|
|
strmux_cfg.dma7 = regk_strmux_ser2;
|
|
|
|
else
|
|
|
|
panic("Invalid DMA channel for ser2\n");
|
|
|
|
break;
|
|
|
|
case dma_sser:
|
|
|
|
if (dmanr == 6)
|
|
|
|
strmux_cfg.dma6 = regk_strmux_sser;
|
|
|
|
else if (dmanr == 7)
|
|
|
|
strmux_cfg.dma7 = regk_strmux_sser;
|
|
|
|
else
|
|
|
|
panic("Invalid DMA channel for sser\n");
|
|
|
|
break;
|
|
|
|
case dma_ser4:
|
|
|
|
if (dmanr == 9)
|
|
|
|
strmux_cfg.dma9 = regk_strmux_ser4;
|
|
|
|
else
|
|
|
|
panic("Invalid DMA channel for ser4\n");
|
|
|
|
break;
|
|
|
|
case dma_jpeg:
|
|
|
|
if (dmanr == 9)
|
|
|
|
strmux_cfg.dma9 = regk_strmux_jpeg;
|
|
|
|
else
|
|
|
|
panic("Invalid DMA channel for JPEG\n");
|
|
|
|
break;
|
|
|
|
case dma_h264:
|
|
|
|
if (dmanr == 11)
|
|
|
|
strmux_cfg.dma11 = regk_strmux_h264;
|
|
|
|
else
|
|
|
|
panic("Invalid DMA channel for H264\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
used_dma_channels[dmanr] = 1;
|
|
|
|
used_dma_channels_users[dmanr] = device_id;
|
|
|
|
REG_WR(clkgen, regi_clkgen, 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);
|
|
|
|
}
|