Search code examples
linux-device-driveruartdma

Does the DMA Buffer Size should be same as UART FIFO size?


I have written a driver for a UART in omap4460 panda board running on Linux platform.I have enabled DMA in FIFO mode in UART.My user application transfers 100 bytes of data from user space to kernel buffer(DMA buffer).

As soon as the DMA channel is enabled, data from DMA buffer is copied to FIFO which is then transmitted to TSR of UART.Since my FIFO size is 64bytes,only 64 bytes is transmitted to TSR.

What should I do to transfer remaining bytes from DMA buffer to FIFO?/ IS there any overflow occuring?

Edit: Added some part of configuration code below represents the UART configuration

/* Software reset */
    iowrite32(0x2,uart_vbaddr + UART_SYSC);
    while((ioread32(uart_vbaddr + UART_SYSS) & 0x1)== 0);

    /* FIFOs and DMA Settings */
    lcr = ioread32(uart_vbaddr + UART_LCR);
    iowrite32(UART_MODE_B,uart_vbaddr + UART_LCR);
    efr = ioread32(uart_vbaddr + UART_EFR);
    iowrite32(0x10,uart_vbaddr + UART_EFR);/
    iowrite32(UART_MODE_A,uart_vbaddr + UART_LCR);
    mcr = ioread32(uart_vbaddr + UART_MCR);
    iowrite32(0x40,uart_vbaddr + UART_MCR);
    iowrite32(0x09,uart_vbaddr + UART_FCR);//FIFO not getting enabled here
    iowrite32(UART_MODE_B,uart_vbaddr + UART_LCR);
    iowrite32(0x2,uart_vbaddr + UART_TLR);//to set for 8 spaces
    iowrite32(0x0,uart_vbaddr + UART_SCR);
    iowrite32(efr,uart_vbaddr + UART_EFR);
    iowrite32(UART_MODE_A,uart_vbaddr + UART_LCR);
    iowrite32(mcr,uart_vbaddr + UART_MCR);
    iowrite32(lcr,uart_vbaddr + UART_LCR);

    /* Protocol Baudrate and interrupt settings */
    dll = divisor & 0xFF;
    dlh = divisor >> 8;
    iowrite32(0x7, uart_vbaddr + UART_MDR1);
    mdrdelay();
    iowrite32(UART_MODE_B, uart_vbaddr + UART_LCR);
    iowrite32(dll,uart_vbaddr);
    iowrite32(dlh,uart_vbaddr + UART_DLH);
    iowrite32(lcr_val , uart_vbaddr + UART_LCR);
    iowrite32(0, uart_vbaddr + UART_MDR1);
    mdrdelay();

    iowrite32(0x09,uart_vbaddr + UART_FCR);//So renabling the FIFO again

DMA is configured in the HW SYNC mode.with BS =0 ans FS =0.ie to transfer element by element for each DMA request.

Code below gives the DMA configuration

/* Set the Read Port & Write Port access in CSDP */
csdp_val &= 0x00000000;
iowrite32(csdp_val,dma_map + DMA_CSDP(dma_cha_line));

/* Set the Channel Source & Destination start address */
iowrite32(bus_addr,dma_map + DMA_CSSA(dma_cha_line));
iowrite32(UART4_BASE,dma_map + DMA_CSDA(dma_cha_line));

/* CCR configuration */ 
ccr_val=ioread32(dma_map+DMA_CCR(dma_cha_line))     
ccr_val |=  (0x1 << 24);//Source triggers on the DMA 

/*Frame(5) and Block(18) Synchronisation */
ccr_val &= ~(0x1 << 5);//FS
ccr_val &= ~(0x1 << 18);//BS
ccr_val |= (0x17);//CCR[4:0]
ccr_val |=  (0x1 << 19);//CCR [19:20] 
ccr_val &=  ~(0x1 << 20);//CCR [19:20] 
ccr_val |= (0x1 << 12);//source - post incremented 12:13 
ccr_val &= ~(0x1 << 13);    
ccr_val &= ~(0x3 << 14);//destination- constant address mode 14:15
iowrite32(ccr_val,dma_map + DMA_CCR(dma_cha_line));
ccr_val = ioread32(dma_map + DMA_CCR(dma_cha_line));  
Finally after this initialiasitation.channel is enabled.

Please suggest me if there is any wrong in the initialization as I am getting only 64 bytes also I am unable to trigger the DMA request in any of the mode given in [TRM]http://www.ti.com/lit/ug/swpu235ab/swpu235ab.pdf

Edit:Code revised for Element Synchronisation. 1.In TRM this sentence was observed frequently.What settings?

The DMA settings must correspond to the system LH DMA controller settings to ensure correct operation of this logic.

2.Is this configuration correct ? :

ccr_val |=  (0x1 << 24);//Source triggers on the DMA
To regenrate the DMA request again,shouldn't I configure the DMA as destination triggered instead of source
ccr_val |=  (0x1 << 24);//Destination triggers on the DMA ?

I had tried both the methods,unfortunately the results are same

3.There are 3 ways to configure the trigger level of FIFO.ie FCR/TLR/MDR3 registers.

In this code I have setup using TLR registers.This TLR setup is verified with Interrupt mode.


Solution

  • The DMA is configured in ... Block Synchronisation.

    That is a fundamental error.
    Block synchronization would be for a block device such as a HDD that has a sector buffer to receive the complete block as the data is transferred over the SATA (or PATA) bus in one operation.
    The UART is a character device that transmits one character per operation. The FIFOs exist to ensure that data can be received (prevent overrun) and that data is available for transmission (minimize idle line time). The other end of the serial link has unknown buffering capability. If it does have limited buffering, then flow control (either using hardware RTS/CTS or software XON/XOFF) should be employed.
    A block device would not use flow control. Once you start the block transfer, the transfer must be completed. You cannot "pause" the transfer as you can with a character device.

    Prior to transmission of the data on the serial link, the data has to be transferred from memory to the UART (in this case the Tx FIFO is the intermediate interface to the transmit register). You could use PIO or DMA to perform this transfer.
    For a DMA transfer both the FIFO and DMA controller must be configured to agree on when (and how often) the DMA requests are made and the size of each DMA response.
    Note that the size of the DMA response is not the same as the size of the DMA buffer (as in your question's title) or the size of the DMA transfer as stored in the count register.

    DMA is configured in the HW SYNC mode.with BS =1 ans FS =0.ie to transfer complete block when DMA request is assserted

    Assuming that the DMA transfer for the transmit is setup for a count of 100 and an address of the correct DMA buffer, it seems that the Tx FIFO is issuing a DMA request.
    Then that first DMA response is for the block size of 100 bytes, of which only 64 bytes are actually captured by the FIFO. The remaining bytes of this first DMA response are presumably discarded.
    As the Tx FIFO drains, if it makes another DMA request, then that new request cannot be satisfied because the DMAC considers the transfer "complete". You can check for this condition by examining the DMAC count register. Is the DMAC count register zero or 36, the number of missing (100 - 64) bytes?

    What should I do to transfer remaining bytes from DMA buffer to FIFO?/ IS there any overflow occuring?

    To configure the DMA controller follow the ten steps outlined in section 16.5.3, Hardware-Synchronized Transfer (page 3627) of the TRM on how to configure an LCh to transfer one element per DMA request.

    In summary, setup the Tx FIFO to make a DMA request when there is at least 8 empty spaces, and the DMA channel to respond with a single element of 1 byte.