Please note as of Wednesday, August 15th, 2018 this wiki has been set to read only. If you are a TI Employee and require Edit ability please contact x0211426 from the company directory.

OMAP35x Linux - DSS FAQ

From Texas Instruments Wiki
Jump to: navigation, search

Introduction

The Linux PSP for OMAP35x, AM/DM37x is based on the OMAP3EVM. This page lists the FAQs related to the Linux drivers (both Fbdev and V4L2) Display subsystem.

NOTE: This section lists the FAQs that are generic to OMAP3 DSS and don't depend upon a specific release version.

Tearing artifacts with WAITFORVSYNC ioctl


While supporting one of customer I have discovered that, with WAITFORVSYNC ioctl we see lots of tearing artifacts on LCD output, but WAITFORGO works fine without any issues.

Debugging/Findings -

Technically both, WAITFORVSYNC and WAITFORGO wait on VSYNC interrupt - but there is slight difference in their implementation/processing.

WAITFORGO ioctl ensures that dirty & shadow_dirty flags (software flag) are cleared, making sure that hardware state and software state always stays in sync. It makes 4 attempts to do so – inside loop it checks for dirty flags and call wait_for_vsync API. In ideal usecase scenario it should come out in single iteration.

On the other hand WAITFORVSYNC is unconditional wait on VSYNC interrupt. The processing continues with an assumption that HW and SW states are in sync.

Since WAITFORGO ioctl seems to be working in all conditions I started debugging with it and I observed that dirty and shadow_dirty flags are getting cleared on 2nd attempt in some cases. This forced me to think about the window between VFP start and VSYNC.


Window-betwee-vfp-vsync.png

The timing diagram below explains relationship between VFP and VSYNC:

Omap-dss-timing-diagram.png


In our usecase, VFP is set to 1 (in number of lines) in DSS HW, (see file: panel-sharp-ls037v7dw01.c), the higher the value of VFP, more chances to falling into this window.

Root-cause (How the behavior impact software)-

The DSS registers are shadow registers, meaning: after updating the HW registers software must write 1 to GO_LCD bit to indicate that we are finished with register update and HW can now read it on next VFP start (not the vsync). This is the way software and hardware handshaking is done.

In Linux Display driver, we have 2 flags, dirty and shadow_dirty, first one indicates software bookkeeping registers are updated and later indicates that shadow registers are written but DSS HW has not yet read it (which happens on VFP start).

Now, if the PAN ioctl is called in above mentioned window then DSS hardware is not going to read the shadow register (setting dirty flags), DMA will still happen on old buffer. Then immediately after PAN ioctl we are calling WAITFORVSYNC ioctl, which is unconditional wait for VSYNC interrupt and then application moves on writing to another buffer (which is now same as where DMA is happening). So here we are breaking and going out-of-sync to handle our ping-pong mechanism in application. As soon as the flow breaks, we see the artefacts on screen.


Statistics from Software (Proving possibility of this issue) –

  1. If you reduce the VFP time period to 0, you neither see the artefacts nor hit the above window (as the window is closed).
  2. I have created a patch with printk() placed in a place where - under ideal condition - execution should never reach. This patch clearly proves that, in case of WAITFORVSYNC you are missing the interrupt and hitting above window and with WAITFORGO you iterate twice into loop to make sure that the shadow registers are read by DSS hardware.

diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index b31d02d..91e0bf6 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -619,6 +619,8 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
                        break;
                }

+               if (i >= 1)
+                       // Control should not reach here: 
+                       // This indicates that we missed one VSYNC interrupt.
+                       printk("%s:%d Oops...i-%d\n", __func__, __LINE__, i);
                /* 4 iterations is the worst case:
                 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
                 * 2 - first VSYNC, dirty = true
@@ -1086,12 +1088,16 @@ static void dss_apply_irq_handler(void *data, u32 mask)
                oc = &dss_cache.overlay_cache[i];
                if (!mgr_busy[oc->channel])
                        oc->shadow_dirty = false;
+               else
+                       // Control should not reach here: 
+                       // This indicates that We received VSYNC interrupt 
+                       // without GO_LCD bit getting cleared
+                       // (without updating overlay internal registers).
+                       printk("%s:%d Oops...\n", __func__, __LINE__);
        }
 
        for (i = 0; i < num_mgrs; ++i) {
                mc = &dss_cache.manager_cache[i];
                if (!mgr_busy[i])
                        mc->shadow_dirty = false;
+               else
+                       // Control should not reach here: 
+                       // This indicates that We received VSYNC interrupt 
+                       // without GO_LCD bit getting cleared
+                       // (without updating overlay internal registers).
+                       printk("%s:%d Oops...\n", __func__, __LINE__);
        }

        r = configure_dispc();

One line summary –

Based on this observation and in the given use-case, We should always use WAITFORGO ioctl since WAITFORVSYNC exposes possible window where software can go out-of-sync with HW as far as buffer management is concerned.


Suggestions/Recommendation -

From User application point of view, user won't care about driver internal implementation. Application will believe that WAITFORVSYNC only returns after displaying (DMAing) previous buffer and now with addition to FBIO_WAITFORVSYNC standard ioctl interface this is very well expected from user application.

I would recommend to merge WAITFORGO with WAITFORVSYNC, kill WAITFORGO (since we have FBIO_WAITFORVSYNC standard ioctl), and anyway WAITFORGO ioctl is OMAP specific custom ioctl.

NOTE: This needs to be followed up and aligned with community before making any changes.