This set of patch is about planes. It bring the support of the atomic_check for the planes. It also fix some bugs around cursor and gdp.
Bich Hemon (2): drm/sti: fallback for GDP scaling drm/sti: adapt YUV colorspace in display pipeline
Fabien Dessenne (1): drm/sti: force cursor CLUT fetch
Vincent Abriou (2): drm/sti: GDP cropping fails when we remove 2 pixels horizontally drm/sti: implement atomic_check for the planes
drivers/gpu/drm/sti/sti_cursor.c | 101 +++++++++++------- drivers/gpu/drm/sti/sti_gdp.c | 216 +++++++++++++++++++++++++-------------- drivers/gpu/drm/sti/sti_hqvdp.c | 175 +++++++++++++++++++------------ drivers/gpu/drm/sti/sti_tvout.c | 61 +++++++---- drivers/gpu/drm/sti/sti_vid.c | 31 ++++-- 5 files changed, 373 insertions(+), 211 deletions(-)
From: Bich Hemon bich.hemon@st.com
When a GDP gets a scale request (which it does not support), it accepts it but crops or clamps and outputs a warning message.
Signed-off-by: Bich Hemon bich.hemon@st.com --- drivers/gpu/drm/sti/sti_gdp.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index a34284be..0a696ad 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -361,6 +361,31 @@ static void sti_gdp_init(struct sti_gdp *gdp) } }
+/** + * sti_gdp_get_dst + * @dev: device + * @dst: requested destination size + * @src: source size + * + * Return the cropped / clamped destination size + * + * RETURNS: + * cropped / clamped destination size + */ +static int sti_gdp_get_dst(struct device *dev, int dst, int src) +{ + if (dst == src) + return dst; + + if (dst < src) { + dev_dbg(dev, "WARNING: GDP scale not supported, will crop\n"); + return dst; + } + + dev_dbg(dev, "WARNING: GDP scale not supported, will clamp\n"); + return src; +} + static void sti_gdp_atomic_update(struct drm_plane *drm_plane, struct drm_plane_state *oldstate) { @@ -399,8 +424,8 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, /* src_x are in 16.16 format */ src_x = state->src_x >> 16; src_y = state->src_y >> 16; - src_w = state->src_w >> 16; - src_h = state->src_h >> 16; + src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX); + src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX);
DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer), @@ -448,10 +473,11 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
/* input parameters */ top_field->gam_gdp_pmp = fb->pitches[0]; - top_field->gam_gdp_size = clamp_val(src_h, 0, GAM_GDP_SIZE_MAX) << 16 | - clamp_val(src_w, 0, GAM_GDP_SIZE_MAX); + top_field->gam_gdp_size = src_h << 16 | src_w;
- /* output parameters */ + /* output parameters (clamped / cropped) */ + dst_w = sti_gdp_get_dst(gdp->dev, dst_w, src_w); + dst_h = sti_gdp_get_dst(gdp->dev, dst_h, src_h); ydo = sti_vtg_get_line_number(*mode, dst_y); yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1); xdo = sti_vtg_get_pixel_number(*mode, dst_x);
GDP source width should be equal to the destination width to get rid of this issue.
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_gdp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 0a696ad..6c1a695 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -471,10 +471,6 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, top_field->gam_gdp_pml += src_x * (bpp >> 3); top_field->gam_gdp_pml += src_y * fb->pitches[0];
- /* input parameters */ - top_field->gam_gdp_pmp = fb->pitches[0]; - top_field->gam_gdp_size = src_h << 16 | src_w; - /* output parameters (clamped / cropped) */ dst_w = sti_gdp_get_dst(gdp->dev, dst_w, src_w); dst_h = sti_gdp_get_dst(gdp->dev, dst_h, src_h); @@ -485,6 +481,11 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, top_field->gam_gdp_vpo = (ydo << 16) | xdo; top_field->gam_gdp_vps = (yds << 16) | xds;
+ /* input parameters */ + src_w = dst_w; + top_field->gam_gdp_pmp = fb->pitches[0]; + top_field->gam_gdp_size = src_h << 16 | src_w; + /* Same content and chained together */ memcpy(btm_field, top_field, sizeof(*btm_field)); top_field->gam_gdp_nvn = list->btm_field_paddr;
From: Fabien Dessenne fabien.dessenne@st.com
It may happen that the cursor is displayed with wrong colors which can be explained by a CLUT wrongly fetched at the first display. Fetching the CLUT at each commit (=move) ensures that the right colors are used, at least from the first cursor move.
Signed-off-by: Fabien Dessenne fabien.dessenne@st.com --- drivers/gpu/drm/sti/sti_cursor.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index a19693a..8cac640 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -127,7 +127,6 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, /* src_x are in 16.16 format */ int src_w = state->src_w >> 16; int src_h = state->src_h >> 16; - bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; struct drm_gem_cma_object *cma_obj; u32 y, x; u32 val; @@ -193,12 +192,6 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, val = y << 16 | x; writel(val, cursor->regs + CUR_AWE);
- if (first_prepare) { - /* Set and fetch CLUT */ - writel(cursor->clut_paddr, cursor->regs + CUR_CML); - writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL); - } - /* Set memory location, size, and position */ writel(cursor->pixmap.paddr, cursor->regs + CUR_PML); writel(cursor->width, cursor->regs + CUR_PMP); @@ -208,6 +201,10 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, x = sti_vtg_get_pixel_number(*mode, dst_x); writel((y << 16) | x, cursor->regs + CUR_VPO);
+ /* Set and fetch CLUT */ + writel(cursor->clut_paddr, cursor->regs + CUR_CML); + writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL); + plane->status = STI_PLANE_UPDATED; }
Atomic update should never fail. Thus all checks must be done in the atomic_check function for each plane (gdp, hqvdp and cursor).
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_cursor.c | 90 +++++++++++++------- drivers/gpu/drm/sti/sti_gdp.c | 173 ++++++++++++++++++++++---------------- drivers/gpu/drm/sti/sti_hqvdp.c | 175 ++++++++++++++++++++++++--------------- 3 files changed, 270 insertions(+), 168 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index 8cac640..a4c67ab 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -5,12 +5,10 @@ * for STMicroelectronics. * License terms: GNU General Public License (GPL), version 2 */ -#include <drm/drmP.h>
-#include <drm/drm_atomic_helper.h> +#include <drm/drm_atomic.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h>
#include "sti_compositor.h" #include "sti_cursor.h" @@ -110,34 +108,31 @@ static void sti_cursor_init(struct sti_cursor *cursor) (b * 5); }
-static void sti_cursor_atomic_update(struct drm_plane *drm_plane, - struct drm_plane_state *oldstate) +static int sti_cursor_atomic_check(struct drm_plane *drm_plane, + struct drm_plane_state *state) { - struct drm_plane_state *state = drm_plane->state; struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_cursor *cursor = to_sti_cursor(plane); struct drm_crtc *crtc = state->crtc; - struct sti_mixer *mixer = to_sti_mixer(crtc); struct drm_framebuffer *fb = state->fb; - struct drm_display_mode *mode = &crtc->mode; - int dst_x = state->crtc_x; - int dst_y = state->crtc_y; - int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); - int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); + struct drm_crtc_state *crtc_state; + struct drm_display_mode *mode; + int dst_x, dst_y, dst_w, dst_h; + int src_w, src_h; + + /* no need for further checks if the plane is being disabled */ + if (!crtc || !fb) + return 0; + + crtc_state = drm_atomic_get_crtc_state(state->state, crtc); + mode = &crtc_state->mode; + dst_x = state->crtc_x; + dst_y = state->crtc_y; + dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); + dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); /* src_x are in 16.16 format */ - int src_w = state->src_w >> 16; - int src_h = state->src_h >> 16; - struct drm_gem_cma_object *cma_obj; - u32 y, x; - u32 val; - - DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", - crtc->base.id, sti_mixer_to_str(mixer), - drm_plane->base.id, sti_plane_to_str(plane)); - DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y); - - dev_dbg(cursor->dev, "%s %s\n", __func__, - sti_plane_to_str(plane)); + src_w = state->src_w >> 16; + src_h = state->src_h >> 16;
if (src_w < STI_CURS_MIN_SIZE || src_h < STI_CURS_MIN_SIZE || @@ -145,7 +140,7 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, src_h > STI_CURS_MAX_SIZE) { DRM_ERROR("Invalid cursor size (%dx%d)\n", src_w, src_h); - return; + return -EINVAL; }
/* If the cursor size has changed, re-allocated the pixmap */ @@ -169,16 +164,46 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, GFP_KERNEL | GFP_DMA); if (!cursor->pixmap.base) { DRM_ERROR("Failed to allocate memory for pixmap\n"); - return; + return -EINVAL; } }
- cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - if (!cma_obj) { + if (!drm_fb_cma_get_gem_obj(fb, 0)) { DRM_ERROR("Can't get CMA GEM object for fb\n"); - return; + return -EINVAL; }
+ DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", + crtc->base.id, sti_mixer_to_str(to_sti_mixer(crtc)), + drm_plane->base.id, sti_plane_to_str(plane)); + DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y); + + return 0; +} + +static void sti_cursor_atomic_update(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct drm_plane_state *state = drm_plane->state; + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_cursor *cursor = to_sti_cursor(plane); + struct drm_crtc *crtc = state->crtc; + struct drm_framebuffer *fb = state->fb; + struct drm_display_mode *mode; + int dst_x, dst_y; + struct drm_gem_cma_object *cma_obj; + u32 y, x; + u32 val; + + if (!crtc || !fb) + return; + + mode = &crtc->mode; + dst_x = state->crtc_x; + dst_y = state->crtc_y; + + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + /* Convert ARGB8888 to CLUT8 */ sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr);
@@ -212,7 +237,6 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane, struct drm_plane_state *oldstate) { struct sti_plane *plane = to_sti_plane(drm_plane); - struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
if (!drm_plane->crtc) { DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", @@ -221,13 +245,15 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane, }
DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", - drm_plane->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->crtc->base.id, + sti_mixer_to_str(to_sti_mixer(drm_plane->crtc)), drm_plane->base.id, sti_plane_to_str(plane));
plane->status = STI_PLANE_DISABLING; }
static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = { + .atomic_check = sti_cursor_atomic_check, .atomic_update = sti_cursor_atomic_update, .atomic_disable = sti_cursor_atomic_disable, }; diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 6c1a695..a6fba9c 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -6,9 +6,7 @@ * License terms: GNU General Public License (GPL), version 2 */
-#include <linux/clk.h> -#include <linux/dma-mapping.h> - +#include <drm/drm_atomic.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
@@ -386,20 +384,115 @@ static int sti_gdp_get_dst(struct device *dev, int dst, int src) return src; }
-static void sti_gdp_atomic_update(struct drm_plane *drm_plane, - struct drm_plane_state *oldstate) +static int sti_gdp_atomic_check(struct drm_plane *drm_plane, + struct drm_plane_state *state) { - struct drm_plane_state *state = drm_plane->state; struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_gdp *gdp = to_sti_gdp(plane); struct drm_crtc *crtc = state->crtc; struct sti_compositor *compo = dev_get_drvdata(gdp->dev); struct drm_framebuffer *fb = state->fb; bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; + struct drm_crtc_state *crtc_state; struct sti_mixer *mixer; struct drm_display_mode *mode; int dst_x, dst_y, dst_w, dst_h; int src_x, src_y, src_w, src_h; + int format; + + /* no need for further checks if the plane is being disabled */ + if (!crtc || !fb) + return 0; + + mixer = to_sti_mixer(crtc); + crtc_state = drm_atomic_get_crtc_state(state->state, crtc); + mode = &crtc_state->mode; + dst_x = state->crtc_x; + dst_y = state->crtc_y; + dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); + dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); + /* src_x are in 16.16 format */ + src_x = state->src_x >> 16; + src_y = state->src_y >> 16; + src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX); + src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX); + + format = sti_gdp_fourcc2format(fb->pixel_format); + if (format == -1) { + DRM_ERROR("Format not supported by GDP %.4s\n", + (char *)&fb->pixel_format); + return -EINVAL; + } + + if (!drm_fb_cma_get_gem_obj(fb, 0)) { + DRM_ERROR("Can't get CMA GEM object for fb\n"); + return -EINVAL; + } + + if (first_prepare) { + /* Register gdp callback */ + gdp->vtg = mixer->id == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux; + if (sti_vtg_register_client(gdp->vtg, + &gdp->vtg_field_nb, crtc)) { + DRM_ERROR("Cannot register VTG notifier\n"); + return -EINVAL; + } + + /* Set and enable gdp clock */ + if (gdp->clk_pix) { + struct clk *clkp; + int rate = mode->clock * 1000; + int res; + + /* + * According to the mixer used, the gdp pixel clock + * should have a different parent clock. + */ + if (mixer->id == STI_MIXER_MAIN) + clkp = gdp->clk_main_parent; + else + clkp = gdp->clk_aux_parent; + + if (clkp) + clk_set_parent(gdp->clk_pix, clkp); + + res = clk_set_rate(gdp->clk_pix, rate); + if (res < 0) { + DRM_ERROR("Cannot set rate (%dHz) for gdp\n", + rate); + return -EINVAL; + } + + if (clk_prepare_enable(gdp->clk_pix)) { + DRM_ERROR("Failed to prepare/enable gdp\n"); + return -EINVAL; + } + } + } + + DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", + crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", + sti_plane_to_str(plane), + dst_w, dst_h, dst_x, dst_y, + src_w, src_h, src_x, src_y); + + return 0; +} + +static void sti_gdp_atomic_update(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct drm_plane_state *state = drm_plane->state; + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_gdp *gdp = to_sti_gdp(plane); + struct drm_crtc *crtc = state->crtc; + struct drm_framebuffer *fb = state->fb; + struct drm_display_mode *mode; + int dst_x, dst_y, dst_w, dst_h; + int src_x, src_y, src_w, src_h; struct drm_gem_cma_object *cma_obj; struct sti_gdp_node_list *list; struct sti_gdp_node_list *curr_list; @@ -409,13 +502,10 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, int format; unsigned int depth, bpp; u32 ydo, xdo, yds, xds; - int res;
- /* Manage the case where crtc is null (disabled) */ - if (!crtc) + if (!crtc || !fb) return;
- mixer = to_sti_mixer(crtc); mode = &crtc->mode; dst_x = state->crtc_x; dst_y = state->crtc_y; @@ -427,14 +517,6 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX); src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX);
- DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", - crtc->base.id, sti_mixer_to_str(mixer), - drm_plane->base.id, sti_plane_to_str(plane)); - DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", - sti_plane_to_str(plane), - dst_w, dst_h, dst_x, dst_y, - src_w, src_h, src_x, src_y); - list = sti_gdp_get_free_nodes(gdp); top_field = list->top_field; btm_field = list->btm_field; @@ -446,20 +528,11 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; format = sti_gdp_fourcc2format(fb->pixel_format); - if (format == -1) { - DRM_ERROR("Format not supported by GDP %.4s\n", - (char *)&fb->pixel_format); - return; - } top_field->gam_gdp_ctl |= format; top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format); top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - if (!cma_obj) { - DRM_ERROR("Can't get CMA GEM object for fb\n"); - return; - }
DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, (char *)&fb->pixel_format, @@ -496,47 +569,6 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, btm_field->gam_gdp_pml = top_field->gam_gdp_pml + fb->pitches[0];
- if (first_prepare) { - /* Register gdp callback */ - gdp->vtg = mixer->id == STI_MIXER_MAIN ? - compo->vtg_main : compo->vtg_aux; - - if (sti_vtg_register_client(gdp->vtg == STI_MIXER_MAIN ? - compo->vtg_main : compo->vtg_aux, - &gdp->vtg_field_nb, crtc)) { - DRM_ERROR("Cannot register VTG notifier\n"); - return; - } - - /* Set and enable gdp clock */ - if (gdp->clk_pix) { - struct clk *clkp; - int rate = mode->clock * 1000; - - /* According to the mixer used, the gdp pixel clock - * should have a different parent clock. */ - if (mixer->id == STI_MIXER_MAIN) - clkp = gdp->clk_main_parent; - else - clkp = gdp->clk_aux_parent; - - if (clkp) - clk_set_parent(gdp->clk_pix, clkp); - - res = clk_set_rate(gdp->clk_pix, rate); - if (res < 0) { - DRM_ERROR("Cannot set rate (%dHz) for gdp\n", - rate); - return; - } - - if (clk_prepare_enable(gdp->clk_pix)) { - DRM_ERROR("Failed to prepare/enable gdp\n"); - return; - } - } - } - /* Update the NVN field of the 'right' field of the current GDP node * (being used by the HW) with the address of the updated ('free') top * field GDP node. @@ -592,7 +624,6 @@ static void sti_gdp_atomic_disable(struct drm_plane *drm_plane, struct drm_plane_state *oldstate) { struct sti_plane *plane = to_sti_plane(drm_plane); - struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
if (!drm_plane->crtc) { DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", @@ -601,13 +632,15 @@ static void sti_gdp_atomic_disable(struct drm_plane *drm_plane, }
DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", - drm_plane->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->crtc->base.id, + sti_mixer_to_str(to_sti_mixer(drm_plane->crtc)), drm_plane->base.id, sti_plane_to_str(plane));
plane->status = STI_PLANE_DISABLING; }
static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = { + .atomic_check = sti_gdp_atomic_check, .atomic_update = sti_gdp_atomic_update, .atomic_disable = sti_gdp_atomic_disable, }; diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 284af75..eace56d 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -4,14 +4,11 @@ * License terms: GNU General Public License (GPL), version 2 */
-#include <linux/clk.h> #include <linux/component.h> #include <linux/firmware.h> -#include <linux/module.h> -#include <linux/platform_device.h> #include <linux/reset.h>
-#include <drm/drmP.h> +#include <drm/drm_atomic.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
@@ -670,7 +667,7 @@ static void sti_hqvdp_start_xp70(struct sti_hqvdp *hqvdp) DRM_DEBUG_DRIVER("\n");
if (hqvdp->xp70_initialized) { - DRM_INFO("HQVDP XP70 already initialized\n"); + DRM_DEBUG_DRIVER("HQVDP XP70 already initialized\n"); return; }
@@ -775,39 +772,124 @@ out: release_firmware(firmware); }
-static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, - struct drm_plane_state *oldstate) +static int sti_hqvdp_atomic_check(struct drm_plane *drm_plane, + struct drm_plane_state *state) { - struct drm_plane_state *state = drm_plane->state; struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); struct drm_crtc *crtc = state->crtc; - struct sti_mixer *mixer = to_sti_mixer(crtc); struct drm_framebuffer *fb = state->fb; - struct drm_display_mode *mode = &crtc->mode; - int dst_x = state->crtc_x; - int dst_y = state->crtc_y; - int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); - int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); - /* src_x are in 16.16 format */ - int src_x = state->src_x >> 16; - int src_y = state->src_y >> 16; - int src_w = state->src_w >> 16; - int src_h = state->src_h >> 16; bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; - struct drm_gem_cma_object *cma_obj; - struct sti_hqvdp_cmd *cmd; - int scale_h, scale_v; - int cmd_offset; + struct drm_crtc_state *crtc_state; + struct drm_display_mode *mode; + int dst_x, dst_y, dst_w, dst_h; + int src_x, src_y, src_w, src_h; + + /* no need for further checks if the plane is being disabled */ + if (!crtc || !fb) + return 0; + + crtc_state = drm_atomic_get_crtc_state(state->state, crtc); + mode = &crtc_state->mode; + dst_x = state->crtc_x; + dst_y = state->crtc_y; + dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); + dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); + /* src_x are in 16.16 format */ + src_x = state->src_x >> 16; + src_y = state->src_y >> 16; + src_w = state->src_w >> 16; + src_h = state->src_h >> 16; + + if (!sti_hqvdp_check_hw_scaling(hqvdp, mode, + src_w, src_h, + dst_w, dst_h)) { + DRM_ERROR("Scaling beyond HW capabilities\n"); + return -EINVAL; + } + + if (!drm_fb_cma_get_gem_obj(fb, 0)) { + DRM_ERROR("Can't get CMA GEM object for fb\n"); + return -EINVAL; + } + + /* + * Input / output size + * Align to upper even value + */ + dst_w = ALIGN(dst_w, 2); + dst_h = ALIGN(dst_h, 2); + + if ((src_w > MAX_WIDTH) || (src_w < MIN_WIDTH) || + (src_h > MAX_HEIGHT) || (src_h < MIN_HEIGHT) || + (dst_w > MAX_WIDTH) || (dst_w < MIN_WIDTH) || + (dst_h > MAX_HEIGHT) || (dst_h < MIN_HEIGHT)) { + DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n", + src_w, src_h, + dst_w, dst_h); + return -EINVAL; + } + + if (first_prepare) { + /* Start HQVDP XP70 coprocessor */ + sti_hqvdp_start_xp70(hqvdp); + + /* Prevent VTG shutdown */ + if (clk_prepare_enable(hqvdp->clk_pix_main)) { + DRM_ERROR("Failed to prepare/enable pix main clk\n"); + return -EINVAL; + } + + /* Register VTG Vsync callback to handle bottom fields */ + if (sti_vtg_register_client(hqvdp->vtg, + &hqvdp->vtg_nb, + crtc)) { + DRM_ERROR("Cannot register VTG notifier\n"); + return -EINVAL; + } + }
DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", - crtc->base.id, sti_mixer_to_str(mixer), + crtc->base.id, sti_mixer_to_str(to_sti_mixer(crtc)), drm_plane->base.id, sti_plane_to_str(plane)); DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", sti_plane_to_str(plane), dst_w, dst_h, dst_x, dst_y, src_w, src_h, src_x, src_y);
+ return 0; +} + +static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct drm_plane_state *state = drm_plane->state; + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); + struct drm_crtc *crtc = state->crtc; + struct drm_framebuffer *fb = state->fb; + struct drm_display_mode *mode; + int dst_x, dst_y, dst_w, dst_h; + int src_x, src_y, src_w, src_h; + struct drm_gem_cma_object *cma_obj; + struct sti_hqvdp_cmd *cmd; + int scale_h, scale_v; + int cmd_offset; + + if (!crtc || !fb) + return; + + mode = &crtc->mode; + dst_x = state->crtc_x; + dst_y = state->crtc_y; + dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); + dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); + /* src_x are in 16.16 format */ + src_x = state->src_x >> 16; + src_y = state->src_y >> 16; + src_w = state->src_w >> 16; + src_h = state->src_h >> 16; + cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); if (cmd_offset == -1) { DRM_DEBUG_DRIVER("Warning: no cmd, will skip frame\n"); @@ -815,13 +897,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, } cmd = hqvdp->hqvdp_cmd + cmd_offset;
- if (!sti_hqvdp_check_hw_scaling(hqvdp, mode, - src_w, src_h, - dst_w, dst_h)) { - DRM_ERROR("Scaling beyond HW capabilities\n"); - return; - } - /* Static parameters, defaulting to progressive mode */ cmd->top.config = TOP_CONFIG_PROGRESSIVE; cmd->top.mem_format = TOP_MEM_FORMAT_DFLT; @@ -836,10 +911,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT;
cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - if (!cma_obj) { - DRM_ERROR("Can't get CMA GEM object for fb\n"); - return; - }
DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, (char *)&fb->pixel_format, @@ -860,16 +931,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, dst_w = ALIGN(dst_w, 2); dst_h = ALIGN(dst_h, 2);
- if ((src_w > MAX_WIDTH) || (src_w < MIN_WIDTH) || - (src_h > MAX_HEIGHT) || (src_h < MIN_HEIGHT) || - (dst_w > MAX_WIDTH) || (dst_w < MIN_WIDTH) || - (dst_h > MAX_HEIGHT) || (dst_h < MIN_HEIGHT)) { - DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n", - src_w, src_h, - dst_w, dst_h); - return; - } - cmd->top.input_viewport_size = src_h << 16 | src_w; cmd->top.input_frame_size = src_h << 16 | src_w; cmd->hvsrc.output_picture_size = dst_h << 16 | dst_w; @@ -900,25 +961,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, scale_v = SCALE_FACTOR * dst_h / src_h; sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
- if (first_prepare) { - /* Start HQVDP XP70 coprocessor */ - sti_hqvdp_start_xp70(hqvdp); - - /* Prevent VTG shutdown */ - if (clk_prepare_enable(hqvdp->clk_pix_main)) { - DRM_ERROR("Failed to prepare/enable pix main clk\n"); - return; - } - - /* Register VTG Vsync callback to handle bottom fields */ - if (sti_vtg_register_client(hqvdp->vtg, - &hqvdp->vtg_nb, - crtc)) { - DRM_ERROR("Cannot register VTG notifier\n"); - return; - } - } - writel(hqvdp->hqvdp_cmd_paddr + cmd_offset, hqvdp->regs + HQVDP_MBX_NEXT_CMD);
@@ -938,7 +980,6 @@ static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane, struct drm_plane_state *oldstate) { struct sti_plane *plane = to_sti_plane(drm_plane); - struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
if (!drm_plane->crtc) { DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", @@ -947,13 +988,15 @@ static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane, }
DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", - drm_plane->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->crtc->base.id, + sti_mixer_to_str(to_sti_mixer(drm_plane->crtc)), drm_plane->base.id, sti_plane_to_str(plane));
plane->status = STI_PLANE_DISABLING; }
static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = { + .atomic_check = sti_hqvdp_atomic_check, .atomic_update = sti_hqvdp_atomic_update, .atomic_disable = sti_hqvdp_atomic_disable, };
From: Bich Hemon bich.hemon@st.com
Use BT601 for SD/ED resolution and BT709 for HD resolution
Signed-off-by: Bich Hemon bich.hemon@st.com --- drivers/gpu/drm/sti/sti_tvout.c | 61 ++++++++++++++++++++++++++--------------- drivers/gpu/drm/sti/sti_vid.c | 31 +++++++++++++++++---- 2 files changed, 64 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index 4c52259..1c27a2c 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -95,6 +95,8 @@
#define ENCODER_CRTC_MASK (BIT(0) | BIT(1))
+#define TVO_MIN_HD_HEIGHT 720 + /* enum listing the supported output data format */ enum sti_tvout_video_out_type { STI_TVOUT_VIDEO_OUT_RGB, @@ -258,6 +260,31 @@ static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout, }
/** + * Set preformatter matrix + * + * @tvout: tvout structure + * @mode: display mode structure + */ +static void tvout_preformatter_set_matrix(struct sti_tvout *tvout, + struct drm_display_mode *mode) +{ + unsigned int i; + const u32 *pf_matrix; + + if (mode->vdisplay >= TVO_MIN_HD_HEIGHT) + pf_matrix = rgb_to_ycbcr_709; + else + pf_matrix = rgb_to_ycbcr_601; + + for (i = 0; i < 8; i++) { + tvout_write(tvout, *(pf_matrix + i), + TVO_CSC_MAIN_M0 + (i * 4)); + tvout_write(tvout, *(pf_matrix + i), + TVO_CSC_AUX_M0 + (i * 4)); + } +} + +/** * Start VIP block for DVO output * * @tvout: pointer on tvout structure @@ -454,10 +481,6 @@ static void sti_tvout_encoder_mode_set(struct drm_encoder *encoder, { }
-static void sti_tvout_encoder_prepare(struct drm_encoder *encoder) -{ -} - static void sti_tvout_encoder_destroy(struct drm_encoder *encoder) { struct sti_tvout_encoder *sti_encoder = to_sti_tvout_encoder(encoder); @@ -470,10 +493,12 @@ static const struct drm_encoder_funcs sti_tvout_encoder_funcs = { .destroy = sti_tvout_encoder_destroy, };
-static void sti_dvo_encoder_commit(struct drm_encoder *encoder) +static void sti_dvo_encoder_enable(struct drm_encoder *encoder) { struct sti_tvout *tvout = to_sti_tvout(encoder);
+ tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode); + tvout_dvo_start(tvout, sti_crtc_is_main(encoder->crtc)); }
@@ -489,8 +514,7 @@ static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = { .dpms = sti_tvout_encoder_dpms, .mode_fixup = sti_tvout_encoder_mode_fixup, .mode_set = sti_tvout_encoder_mode_set, - .prepare = sti_tvout_encoder_prepare, - .commit = sti_dvo_encoder_commit, + .enable = sti_dvo_encoder_enable, .disable = sti_dvo_encoder_disable, };
@@ -521,10 +545,12 @@ sti_tvout_create_dvo_encoder(struct drm_device *dev, return drm_encoder; }
-static void sti_hda_encoder_commit(struct drm_encoder *encoder) +static void sti_hda_encoder_enable(struct drm_encoder *encoder) { struct sti_tvout *tvout = to_sti_tvout(encoder);
+ tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode); + tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc)); }
@@ -543,8 +569,7 @@ static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = { .dpms = sti_tvout_encoder_dpms, .mode_fixup = sti_tvout_encoder_mode_fixup, .mode_set = sti_tvout_encoder_mode_set, - .prepare = sti_tvout_encoder_prepare, - .commit = sti_hda_encoder_commit, + .commit = sti_hda_encoder_enable, .disable = sti_hda_encoder_disable, };
@@ -573,10 +598,12 @@ static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev, return drm_encoder; }
-static void sti_hdmi_encoder_commit(struct drm_encoder *encoder) +static void sti_hdmi_encoder_enable(struct drm_encoder *encoder) { struct sti_tvout *tvout = to_sti_tvout(encoder);
+ tvout_preformatter_set_matrix(tvout, &encoder->crtc->mode); + tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc)); }
@@ -592,8 +619,7 @@ static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = { .dpms = sti_tvout_encoder_dpms, .mode_fixup = sti_tvout_encoder_mode_fixup, .mode_set = sti_tvout_encoder_mode_set, - .prepare = sti_tvout_encoder_prepare, - .commit = sti_hdmi_encoder_commit, + .commit = sti_hdmi_encoder_enable, .disable = sti_hdmi_encoder_disable, };
@@ -645,18 +671,9 @@ static int sti_tvout_bind(struct device *dev, struct device *master, void *data) { struct sti_tvout *tvout = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - unsigned int i;
tvout->drm_dev = drm_dev;
- /* set preformatter matrix */ - for (i = 0; i < 8; i++) { - tvout_write(tvout, rgb_to_ycbcr_601[i], - TVO_CSC_MAIN_M0 + (i * 4)); - tvout_write(tvout, rgb_to_ycbcr_601[i], - TVO_CSC_AUX_M0 + (i * 4)); - } - sti_tvout_create_encoders(drm_dev, tvout);
return 0; diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c index a8254cc..0a1e50c 100644 --- a/drivers/gpu/drm/sti/sti_vid.c +++ b/drivers/gpu/drm/sti/sti_vid.c @@ -42,6 +42,17 @@ #define VID_MPR1_BT709 0x0AC50000 #define VID_MPR2_BT709 0x07150545 #define VID_MPR3_BT709 0x00000AE8 +/* YCbCr to RGB BT709: + * R = Y+1.3711Cr + * G = Y-0.6992Cr-0.3359Cb + * B = Y+1.7344Cb + */ +#define VID_MPR0_BT601 0x0A800000 +#define VID_MPR1_BT601 0x0AAF0000 +#define VID_MPR2_BT601 0x094E0754 +#define VID_MPR3_BT601 0x00000ADD + +#define VID_MIN_HD_HEIGHT 720
void sti_vid_commit(struct sti_vid *vid, struct drm_plane_state *state) @@ -52,6 +63,7 @@ void sti_vid_commit(struct sti_vid *vid, int dst_y = state->crtc_y; int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); + int src_h = state->src_h >> 16; u32 val, ydo, xdo, yds, xds;
/* Input / output size @@ -71,6 +83,19 @@ void sti_vid_commit(struct sti_vid *vid,
writel((ydo << 16) | xdo, vid->regs + VID_VPO); writel((yds << 16) | xds, vid->regs + VID_VPS); + + /* Color conversion parameters */ + if (src_h >= VID_MIN_HD_HEIGHT) { + writel(VID_MPR0_BT709, vid->regs + VID_MPR0); + writel(VID_MPR1_BT709, vid->regs + VID_MPR1); + writel(VID_MPR2_BT709, vid->regs + VID_MPR2); + writel(VID_MPR3_BT709, vid->regs + VID_MPR3); + } else { + writel(VID_MPR0_BT601, vid->regs + VID_MPR0); + writel(VID_MPR1_BT601, vid->regs + VID_MPR1); + writel(VID_MPR2_BT601, vid->regs + VID_MPR2); + writel(VID_MPR3_BT601, vid->regs + VID_MPR3); + } }
void sti_vid_disable(struct sti_vid *vid) @@ -91,12 +116,6 @@ static void sti_vid_init(struct sti_vid *vid) /* Opaque */ writel(VID_ALP_OPAQUE, vid->regs + VID_ALP);
- /* Color conversion parameters */ - writel(VID_MPR0_BT709, vid->regs + VID_MPR0); - writel(VID_MPR1_BT709, vid->regs + VID_MPR1); - writel(VID_MPR2_BT709, vid->regs + VID_MPR2); - writel(VID_MPR3_BT709, vid->regs + VID_MPR3); - /* Brightness, contrast, tint, saturation */ writel(VID_BC_DFLT, vid->regs + VID_BC); writel(VID_TINT_DFLT, vid->regs + VID_TINT);
dri-devel@lists.freedesktop.org