This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

mcbsp dma linked transfer problem in Linux omap3530

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 */