HI all,
I came across a problem lately.
I am configuring the mcbsp to be read using dma in 2.6.32 linux (from ti psp release psp03.00.01.06). The aim is ,
- Three dma buffers shall be filled one after the other by the dma controller.
- Then the appropriate dma buffers (after finding out which dma buffer is ready to be read ) shall be copied to a kernel fifo in the dma read call back handler.
- Then the user space can read the kfifo to the user space via another characeter driver.
I have coded half of the functionality in the plat/mcbsp.c, src (code given below.)
Then came my problem: If i use 3 logical dma channels which are linked as shown below (CODE 1), the dma gives an error after the first dma callback hasndler is invoked- "DMA transaction error with device 32". After that error, the dma is being disabled automatically, it seems.
NOTE: According to dma.h, linux consider dma Device 32 as mcbsp module 1 RX request.
#define OMAP24XX_DMA_MCBSP1_TX 31 /* S_DMA_30 */
#define OMAP24XX_DMA_MCBSP1_RX 32 /* S_DMA_31 */
At the same time, if I link a single logical dma channel to itself as shown ( CODE 2) ,the call back handler is being called properly continuously!!!
What could be the reason? Am i missing something in the dma src/dest/transfer params?
CODE 1
---------
omap_dma_link_lch(dma_rx_ch[0],dma_rx_ch[1]);
omap_dma_link_lch(dma_rx_ch[1],dma_rx_ch[2]);
omap_dma_link_lch(dma_rx_ch[2],dma_rx_ch[0]);
omap_start_dma(mcbsp->dma_rx_lch);
OUTPUT 1
------------
dma_buffer[0] = 0xffc00000; dma_buffer_phy[i]=0x0
mcbsp->dma_rx_lch =0
McBSP1 RX DMA(32) on channel 0
dma_buffer[1] = 0xffc01000; dma_buffer_phy[i]=0x1
McBSP1 RX DMA(32) on channel 1
dma_buffer[2] = 0xffc02000; dma_buffer_phy[i]=0x2
McBSP1 RX DMA(32) on channel 2
dma_buffer[3] = 0xffc03000; dma_buffer_phy[i]=0x3
McBSP1 RX DMA(32) on channel 3
Cleardata driver initialization complete v1.1
Open audio transport
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
DMA transaction error with device 32
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
//then the dma is disabled automatically in the dma driver.
The mcbsp dma read call hack handler is executed properly if I self link one dma channel to itself.!!!!
CODE 2
----------
omap_dma_link_lch(dma_rx_ch[0],dma_rx_ch[0]);
// omap_dma_link_lch(dma_rx_ch[1],dma_rx_ch[2]);
// omap_dma_link_lch(dma_rx_ch[2],dma_rx_ch[0]);
omap_start_dma(mcbsp->dma_rx_lch);
return 0;
OUTPUT 2
----------
dma_buffer[0] = 0xffc00000; dma_buffer_phy[i]=0x0
mcbsp->dma_rx_lch =0
McBSP1 RX DMA(32) on channel 0
dma_buffer[1] = 0xffc01000; dma_buffer_phy[i]=0x1
McBSP1 RX DMA(32) on channel 1
dma_buffer[2] = 0xffc02000; dma_buffer_phy[i]=0x2
McBSP1 RX DMA(32) on channel 2
dma_buffer[3] = 0xffc03000; dma_buffer_phy[i]=0x3
McBSP1 RX DMA(32) on channel 3
Cleardata driver initialization complete v1.1
Open audio transport
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = 0
...
//this continues as long as i write something in the mcbsp
This is the whole code that is being used to configure the dma.( MCBSP is configured as polling.)
--------------------------------------------------------------------------------------------------------------------------------
/*
dma call back dma read
*/
static void cleardata_mcbsp_dma_callback(int lch, u16 ch_status, void *data)
{
struct omap_mcbsp *mcbsp_dma_rx = data;
printk(KERN_INFO "Inside mcbsp dma callback mcbsp_dma_rx->dma_rx_lch = %d\n",mcbsp_dma_rx->dma_rx_lch);
//copy the data from the buffer to a kfifo
}
/*
dma read implementation for cleardata transfer
*/
static dma_addr_t *dma_buffer[10]; //to be declared in a global struct
static unsigned int dma_buffer_phy[10]; //to be declared in a global struct
int dma_rx_ch[10]; //ping pong
static int cleardata_dma_setup(int mcbsp_id)
{
int src_port = 0;
int dest_port = 0;
int sync_dev = 0;
int i;
int dma_data_type;
int noofwords;
int length;
int pg;
void __iomem *base;
struct omap_mcbsp *mcbsp;
if(!omap_mcbsp_check_valid_id(mcbsp_id))
{
printk(KERN_ERR "Error: Invalid McBSP id(%d) specified in DMA setup.\n", mcbsp_id);
return -1;
}
mcbsp = (struct omap_mcbsp *)id_to_mcbsp_ptr(mcbsp_id);
length = 1024;
dma_data_type = OMAP_DMA_DATA_TYPE_S16;
noofwords = length >> dma_data_type;
for(i=0;i<4;i++)
{
pg = get_order(length);
dma_buffer[i] = (dma_addr_t) dma_alloc_coherent (NULL, (size_t)(PAGE_SIZE<<pg), &dma_buffer_phy[i], 0); //dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle);
if (dma_buffer[i]==0)
{
printk(KERN_INFO "dma allocation error i=%d\n",i);
return -EAGAIN;
}
printk(KERN_INFO "dma_buffer[%d] = 0x%x; dma_buffer_phy[i]=0x%x",i,dma_buffer[i],i,dma_buffer_phy[i]);
sync_dev = mcbsp->dma_rx_sync;
if (omap_request_dma(mcbsp->dma_rx_sync, "McBSP RX",
cleardata_mcbsp_dma_callback,
mcbsp,&dma_rx_ch[i]))
{
dev_err(mcbsp->dev, "Unable to request DMA channel for "
"McBSP%d RX. Trying IRQ based RX\n",
mcbsp->id);
return -EAGAIN;
}
if (i==0)
{
mcbsp->dma_rx_lch = dma_rx_ch[i];
printk(KERN_INFO "mcbsp->dma_rx_lch =%x\n",mcbsp->dma_rx_lch);
}
printk(KERN_INFO "McBSP%d RX DMA(%d) on channel %d\n", mcbsp->id, mcbsp->dma_rx_sync, dma_rx_ch[i]);
/*
void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
int frame_count, int sync_mode,
int dma_trigger, int src_or_dst_synch)
*/
omap_set_dma_transfer_params(dma_rx_ch[i],
dma_data_type,
noofwords, 1,
OMAP_DMA_SYNC_ELEMENT, //OMAP_DMA_SYNC_BLOCK
sync_dev, 1); //previously 0; dma triggered by src=0 by dest=1
/*
void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
int frame_count, int sync_mode,
int dma_trigger, int src_or_dst_synch)
*/
omap_set_dma_src_params(mcbsp->dma_rx_lch,
src_port,
OMAP_DMA_AMODE_CONSTANT,
mcbsp->phys_base + OMAP_MCBSP_REG_DRR2,
0, 0); //1,0
/*void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
unsigned long dest_start,
int dst_ei, int dst_fi)
*/
omap_set_dma_dest_params(mcbsp->dma_rx_lch,
dest_port,
OMAP_DMA_AMODE_POST_INC,
dma_buffer_phy[i],
0, 0);
}
omap_dma_link_lch(dma_rx_ch[0],dma_rx_ch[1]);
omap_dma_link_lch(dma_rx_ch[1],dma_rx_ch[2]);
omap_dma_link_lch(dma_rx_ch[2],dma_rx_ch[0]);
omap_start_dma(mcbsp->dma_rx_lch);
return 0;
}
EXPORT_SYMBOL(cleardata_dma_setup);
#define OMAP24XX_DMA_MCBSP1_TX 31 /* S_DMA_30 */
#define OMAP24XX_DMA_MCBSP1_RX 32 /* S_DMA_31 */