]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
drm: stm: implement get_scanout_position function
authorBenjamin Gaignard <benjamin.gaignard@linaro.org>
Fri, 29 Jun 2018 13:01:40 +0000 (15:01 +0200)
committerBenjamin Gaignard <benjamin.gaignard@linaro.org>
Thu, 27 Sep 2018 13:04:26 +0000 (15:04 +0200)
Hardware allow to read the position in scanout buffer so
we can use this information to make wait of vblank more accurate.

Active area bounds (start, end, total height) have already been
computed and written in ltdc registers, read them and get the
current line position to compute vpos value.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Reviewed-by: Yannick Fertré <yannick.fertre@st.com>
Tested-by: Yannick Fertré <yannick.fertre@st.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180629130140.16004-1-benjamin.gaignard@linaro.org
drivers/gpu/drm/stm/drv.c
drivers/gpu/drm/stm/ltdc.c
drivers/gpu/drm/stm/ltdc.h

index f2021b23554d316b5270563fbb45f4ddf939bef9..d05f8f80fe6f6bda3d48e69b951ad4733beda681 100644 (file)
@@ -72,6 +72,8 @@ static struct drm_driver drv_driver = {
        .gem_prime_vmap = drm_gem_cma_prime_vmap,
        .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
        .gem_prime_mmap = drm_gem_cma_prime_mmap,
+       .get_scanout_position = ltdc_crtc_scanoutpos,
+       .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
 };
 
 static int drv_load(struct drm_device *ddev)
index 808d9fb627e97ab07562c17183ade0508abfe0b7..61dd661aa0acbde3abfe9481c9a32f4d20c79240 100644 (file)
 #define IER_TERRIE     BIT(2)          /* Transfer ERRor Interrupt Enable */
 #define IER_RRIE       BIT(3)          /* Register Reload Interrupt enable */
 
+#define CPSR_CYPOS     GENMASK(15, 0)  /* Current Y position */
+
 #define ISR_LIF                BIT(0)          /* Line Interrupt Flag */
 #define ISR_FUIF       BIT(1)          /* Fifo Underrun Interrupt Flag */
 #define ISR_TERRIF     BIT(2)          /* Transfer ERRor Interrupt Flag */
@@ -626,6 +628,49 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
        reg_clear(ldev->regs, LTDC_IER, IER_LIE);
 }
 
+bool ltdc_crtc_scanoutpos(struct drm_device *ddev, unsigned int pipe,
+                         bool in_vblank_irq, int *vpos, int *hpos,
+                         ktime_t *stime, ktime_t *etime,
+                         const struct drm_display_mode *mode)
+{
+       struct ltdc_device *ldev = ddev->dev_private;
+       int line, vactive_start, vactive_end, vtotal;
+
+       if (stime)
+               *stime = ktime_get();
+
+       /* The active area starts after vsync + front porch and ends
+        * at vsync + front porc + display size.
+        * The total height also include back porch.
+        * We have 3 possible cases to handle:
+        * - line < vactive_start: vpos = line - vactive_start and will be
+        * negative
+        * - vactive_start < line < vactive_end: vpos = line - vactive_start
+        * and will be positive
+        * - line > vactive_end: vpos = line - vtotal - vactive_start
+        * and will negative
+        *
+        * Computation for the two first cases are identical so we can
+        * simplify the code and only test if line > vactive_end
+        */
+       line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS;
+       vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP;
+       vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH;
+       vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH;
+
+       if (line > vactive_end)
+               *vpos = line - vtotal - vactive_start;
+       else
+               *vpos = line - vactive_start;
+
+       *hpos = 0;
+
+       if (etime)
+               *etime = ktime_get();
+
+       return true;
+}
+
 static const struct drm_crtc_funcs ltdc_crtc_funcs = {
        .destroy = drm_crtc_cleanup,
        .set_config = drm_atomic_helper_set_config,
index d5afb89608671153681aca3983b0daacca528eda..e46f477a849448dfe2e6f7e04f7d9770ded32de7 100644 (file)
@@ -38,6 +38,11 @@ struct ltdc_device {
        struct fps_info plane_fpsi[LTDC_MAX_LAYER];
 };
 
+bool ltdc_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
+                         bool in_vblank_irq, int *vpos, int *hpos,
+                         ktime_t *stime, ktime_t *etime,
+                         const struct drm_display_mode *mode);
+
 int ltdc_load(struct drm_device *ddev);
 void ltdc_unload(struct drm_device *ddev);