Commit 53273b52 authored by Benjamin Gaignard's avatar Benjamin Gaignard

drm: stm: implement get_scanout_position function

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: default avatarBenjamin Gaignard <benjamin.gaignard@st.com>
Reviewed-by: default avatarYannick Fertré <yannick.fertre@st.com>
Tested-by: default avatarYannick Fertré <yannick.fertre@st.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180629130140.16004-1-benjamin.gaignard@linaro.org
parent 17fd7a9d
...@@ -72,6 +72,8 @@ static struct drm_driver drv_driver = { ...@@ -72,6 +72,8 @@ static struct drm_driver drv_driver = {
.gem_prime_vmap = drm_gem_cma_prime_vmap, .gem_prime_vmap = drm_gem_cma_prime_vmap,
.gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
.gem_prime_mmap = drm_gem_cma_prime_mmap, .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) static int drv_load(struct drm_device *ddev)
......
...@@ -148,6 +148,8 @@ ...@@ -148,6 +148,8 @@
#define IER_TERRIE BIT(2) /* Transfer ERRor Interrupt Enable */ #define IER_TERRIE BIT(2) /* Transfer ERRor Interrupt Enable */
#define IER_RRIE BIT(3) /* Register Reload 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_LIF BIT(0) /* Line Interrupt Flag */
#define ISR_FUIF BIT(1) /* Fifo Underrun Interrupt Flag */ #define ISR_FUIF BIT(1) /* Fifo Underrun Interrupt Flag */
#define ISR_TERRIF BIT(2) /* Transfer ERRor 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) ...@@ -626,6 +628,49 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
reg_clear(ldev->regs, LTDC_IER, IER_LIE); 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 = { static const struct drm_crtc_funcs ltdc_crtc_funcs = {
.destroy = drm_crtc_cleanup, .destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
......
...@@ -38,6 +38,11 @@ struct ltdc_device { ...@@ -38,6 +38,11 @@ struct ltdc_device {
struct fps_info plane_fpsi[LTDC_MAX_LAYER]; 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); int ltdc_load(struct drm_device *ddev);
void ltdc_unload(struct drm_device *ddev); void ltdc_unload(struct drm_device *ddev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment