DA8xx LCDC Linux FB FAQs

From Texas Instruments Wiki
Jump to: navigation, search

About this page

This page describes the flicker/tearing issue faced on AM335x when graphics(SGX)/Android comes up. Also describes root cause and its solution.

Introduction

AM335x LCD controller is based LCDC IP of DA8xx which has 2 DMA channels(channel 0 and channel 1), controller ping pongs between them in dual frame buffer mode on every other channel frame done interrupt. Linux frame buffer driver uses 2 DDR frame buffers as ping pong buffers. And it is expected to feed the filled buffer on every frame done callback.

DMA channel 0/1 ping ponging

After an EOF0 or EOF1 interrupt, it takes a certain latency λ before the ISR can set cfg_fb0_base, cfg_fb0_ceil, cfg_fb1_base, and cfg_fb1_ceil.

Meanwhile, the DMA uses the current values of those registers for the next frame immediately after firing the interrupt. DMA ping pong.jpg


Recommended Ping Pong usage

Two frames, B0 and B1, are needed at the start as shown in below figure. However, B0 can be a black frame (the Host creates a black frame in DDR). In this case, a video display framebuffer must be available at the start and for every ISR. The EOF0 ISR configures fb0 and the EOF1 ISR configures fb1.

Recommended buf usage.jpg


Host CPU Keep Out Regions

The DMA engine uses a base address and a ceiling address to define a framebuffer. It is imperative that these base-ceiling pairs match up when the hardware reads them. Say the Host CPU updates only the base register and has not had a chance to update the ceiling register when the DMA engine does the read. This framebuffer, as understood by the DMA engine, will be way off. It will lead to sync error interrupts and possibly affect system performance. The Red bars denote keep-out regions where the Host CPU cannot update the same config registers that are being read by the DMA engine.

Host keep out red region.jpg

Issue with Linux FB use case

Issue with Linux driver is that it will have 2 user DDR buffers B0 and B1, driver ping pongs between them. Application follows below steps:

  • Opens up /dev/fb0 and does mmap on opened FD for 2 frame size.
  • Gives filled buffer(assume ping) to driver via FB_PAN and waits for next frame done interrupt.
  • On driver getting frame done interrupt, it wakes up the application to fill next buffer(pong).
  • Again application submits filled buffer(pong) buffer to driver and waits for next frame done interrupt.
  • Application on wake up by driver assumes previous buffer(ping) is done and starts filling it again with new data.

And this goes

Steps below describe issue depicted as shown in figure:

  • Initially both DMA channel FB0 and FB1 are programmed for buffer-B0.
  • On EOF0: Program FB0 for buffer-B1 as application would have issued PAN on B1 meanwhile, then indicate(wake up) application to fill up buffer-B0. As FB1 is active and continues to DMA buffer-B0(which is being filled), leading to tearing/flickering issue.
  • On EOF1: Program FB1 for buffer-B0 as application would have issued PAN on B0 meanwhile, then indicate(wake up) application to fill up buffer-B1. As FB0 is active and continues to DMA buffer-B1(which is being filled), leading to tearing/flickering issue and so on..

Orig problem1.jpg

Also we note that frames are displayed with delay of one frame period, which is may not acceptable to the user.

Solution or work around for issue

ISR will update the information about the free DMA channel. On driver getting FB_PAN request from application, configures the free DMA channel so that it will take effect in next frame done interrupt.

Solution.jpg

Limitation with above solution

It is not safe to configure DMA in FB_PAN as it could be the point where hardware is done with previous frame and reading other channel base and ceiling. That is we could be updating in host CPU keep out region. If we hit this situation then we will run in to sync errors. Currently entering to this condition is narrowed down smallest possible extent by disabling system wide interrupts.

Other solution

Having 3 user DDR buffers will also solve the issue. But Android is designed to work with double buffered mode and increasing no. of buffers might lead to UI flickers or inconsistencies in UI output.

Backup section

This section will have

  • Below applications are used for reproducing issue. It pans 2 moving white rectangles on top and bottom of panel on black background.
    • pan_2rect_sa.c application for am335x
    • pan_2rect.c application for da850
  • Moving rectangles show tearing effect.
  • Here is the patch which fixes the issue.

Flicker due to underflow error

  • Apply below patch:
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 0f96b40..3bc7104 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -821,8 +821,8 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
        u32 stat = lcdc_read(LCD_MASKED_STAT_REG);
        u32 reg_int;

-       if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
-               printk(KERN_ERR "LCDC sync lost or underflow error occured\n");
+       if ((stat & LCD_SYNC_LOST) || (stat & LCD_FIFO_UNDERFLOW)) {
++              printk(KERN_ERR "LCDC sync lost or underflow error occured 0x%x\n", lcdc_read(LCD_RAW_STAT_REG));
                lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
                lcdc_write(stat, LCD_MASKED_STAT_REG);
                lcd_enable_raster();
  • Occasional underflow errors were seen on playing mp4 video with mplayer mostly on start and stop of mplayer.
  • Issue is not observed on revision 1.2 of AM335x EVM.
  • Underflow errors reduced on configuring th_fifo_ready to max(512 bytes)
  • Issue disappears on configuring PR_OLD_COUNT field in the EMIF control register(OCP config) to value close to zero.
  • Tuning of dma_master_prio in dma_master control register doesnot help.
  • L3 level initiator priority control – keep LCDC at higher priority. From U-boot
#mw 44e1060c 00c00000 from uboot prompt
  • mreqprio_0 register setting (The MREQPRIO register provides an interface to change the access priorities for the various masters

accessing the EMIF(DDR). Software can make use of this register to set the requestor priorities for required EMIF arbitration.) From U-boot.

#mw 44e10670 44444477
  • Put LCD into Connection ID to Class of Service 1 Mapping Register
REG_CONNID_COS_1_MAP_EN ==> set to 1 to enable
REG_CONNID_1_COS_1 ==> LCDC (0x9)
REG_MSK_1_COS_1 ==> 0 (Disable masking, have only LCDC)

Also raise REG_COS_COUNT_1 priority in OCP_config: value 0x10.