1
votes

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.

1
The FIFO size has no bearing on the DMA buffer size. If the FIFO was only 1 byte long (i.e. no FIFO), would you ask if the DMA buffer should be 1 byte long? The DMA buffer should be sized to the longest message and the max available DMA-able buffer size you can afford to allocate for the USART.sawdust
@sawdust :I was in misconception because,when FIFO was disabled only 1 bytes was transmitted and when enabled 64 bytes was transmitted.Is it something to deal with FIFO configuration/DMA configuration?ddpd
What driver is this? At the HW level, the transmit FIFO should be making DMA requests as the FIFO is drained (and not just the one time at the start). The DMA controller should be satisfying those requests until the transfer count goes to zero. Seems like FIFO or DMAC is not configured properly or the DMA transfer count is wrong.sawdust
@sawdust:The DMA is configured in H/W Synchronisation mode and the synchronisation is chosen as Block Synchronisation ie(as soon as the DMA channel is enabled transfer starts from source to destination address).The transfer counts gives the same number as the bytes given but it is not transmitted in the TX line except 64 bytes(FIFO size).Please have a look at the code.ddpd

1 Answers

2
votes

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.