Commit dd86dc2f authored by Vincent Abriou's avatar Vincent Abriou

drm/sti: implement atomic_check for the planes

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: default avatarVincent Abriou <vincent.abriou@st.com>
Reviewed-by: default avatarBenjamin Gaignard <benjamin.gaignard@linaro.org>
parent 0b9d0416
...@@ -5,12 +5,10 @@ ...@@ -5,12 +5,10 @@
* for STMicroelectronics. * for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2 * 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_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
#include <drm/drm_plane_helper.h>
#include "sti_compositor.h" #include "sti_compositor.h"
#include "sti_cursor.h" #include "sti_cursor.h"
...@@ -110,34 +108,31 @@ static void sti_cursor_init(struct sti_cursor *cursor) ...@@ -110,34 +108,31 @@ static void sti_cursor_init(struct sti_cursor *cursor)
(b * 5); (b * 5);
} }
static void sti_cursor_atomic_update(struct drm_plane *drm_plane, static int sti_cursor_atomic_check(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate) struct drm_plane_state *state)
{ {
struct drm_plane_state *state = drm_plane->state;
struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_plane *plane = to_sti_plane(drm_plane);
struct sti_cursor *cursor = to_sti_cursor(plane); struct sti_cursor *cursor = to_sti_cursor(plane);
struct drm_crtc *crtc = state->crtc; struct drm_crtc *crtc = state->crtc;
struct sti_mixer *mixer = to_sti_mixer(crtc);
struct drm_framebuffer *fb = state->fb; struct drm_framebuffer *fb = state->fb;
struct drm_display_mode *mode = &crtc->mode; struct drm_crtc_state *crtc_state;
int dst_x = state->crtc_x; struct drm_display_mode *mode;
int dst_y = state->crtc_y; int dst_x, dst_y, dst_w, dst_h;
int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); int src_w, src_h;
int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
/* 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 are in 16.16 format */
int src_w = state->src_w >> 16; src_w = state->src_w >> 16;
int src_h = state->src_h >> 16; 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));
if (src_w < STI_CURS_MIN_SIZE || if (src_w < STI_CURS_MIN_SIZE ||
src_h < 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, ...@@ -145,7 +140,7 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
src_h > STI_CURS_MAX_SIZE) { src_h > STI_CURS_MAX_SIZE) {
DRM_ERROR("Invalid cursor size (%dx%d)\n", DRM_ERROR("Invalid cursor size (%dx%d)\n",
src_w, src_h); src_w, src_h);
return; return -EINVAL;
} }
/* If the cursor size has changed, re-allocated the pixmap */ /* 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, ...@@ -169,16 +164,46 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
GFP_KERNEL | GFP_DMA); GFP_KERNEL | GFP_DMA);
if (!cursor->pixmap.base) { if (!cursor->pixmap.base) {
DRM_ERROR("Failed to allocate memory for pixmap\n"); DRM_ERROR("Failed to allocate memory for pixmap\n");
return; return -EINVAL;
} }
} }
cma_obj = drm_fb_cma_get_gem_obj(fb, 0); if (!drm_fb_cma_get_gem_obj(fb, 0)) {
if (!cma_obj) {
DRM_ERROR("Can't get CMA GEM object for fb\n"); 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 */ /* Convert ARGB8888 to CLUT8 */
sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr); 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, ...@@ -212,7 +237,6 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate) struct drm_plane_state *oldstate)
{ {
struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_plane *plane = to_sti_plane(drm_plane);
struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
if (!drm_plane->crtc) { if (!drm_plane->crtc) {
DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
...@@ -221,13 +245,15 @@ static void sti_cursor_atomic_disable(struct drm_plane *drm_plane, ...@@ -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_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)); drm_plane->base.id, sti_plane_to_str(plane));
plane->status = STI_PLANE_DISABLING; plane->status = STI_PLANE_DISABLING;
} }
static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = { static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
.atomic_check = sti_cursor_atomic_check,
.atomic_update = sti_cursor_atomic_update, .atomic_update = sti_cursor_atomic_update,
.atomic_disable = sti_cursor_atomic_disable, .atomic_disable = sti_cursor_atomic_disable,
}; };
......
...@@ -6,9 +6,7 @@ ...@@ -6,9 +6,7 @@
* License terms: GNU General Public License (GPL), version 2 * License terms: GNU General Public License (GPL), version 2
*/ */
#include <linux/clk.h> #include <drm/drm_atomic.h>
#include <linux/dma-mapping.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_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) ...@@ -386,20 +384,115 @@ static int sti_gdp_get_dst(struct device *dev, int dst, int src)
return src; return src;
} }
static void sti_gdp_atomic_update(struct drm_plane *drm_plane, static int sti_gdp_atomic_check(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate) struct drm_plane_state *state)
{ {
struct drm_plane_state *state = drm_plane->state;
struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_plane *plane = to_sti_plane(drm_plane);
struct sti_gdp *gdp = to_sti_gdp(plane); struct sti_gdp *gdp = to_sti_gdp(plane);
struct drm_crtc *crtc = state->crtc; struct drm_crtc *crtc = state->crtc;
struct sti_compositor *compo = dev_get_drvdata(gdp->dev); struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
struct drm_framebuffer *fb = state->fb; struct drm_framebuffer *fb = state->fb;
bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
struct drm_crtc_state *crtc_state;
struct sti_mixer *mixer; struct sti_mixer *mixer;
struct drm_display_mode *mode; struct drm_display_mode *mode;
int dst_x, dst_y, dst_w, dst_h; int dst_x, dst_y, dst_w, dst_h;
int src_x, src_y, src_w, src_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 drm_gem_cma_object *cma_obj;
struct sti_gdp_node_list *list; struct sti_gdp_node_list *list;
struct sti_gdp_node_list *curr_list; struct sti_gdp_node_list *curr_list;
...@@ -409,13 +502,10 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, ...@@ -409,13 +502,10 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
int format; int format;
unsigned int depth, bpp; unsigned int depth, bpp;
u32 ydo, xdo, yds, xds; u32 ydo, xdo, yds, xds;
int res;
/* Manage the case where crtc is null (disabled) */ if (!crtc || !fb)
if (!crtc)
return; return;
mixer = to_sti_mixer(crtc);
mode = &crtc->mode; mode = &crtc->mode;
dst_x = state->crtc_x; dst_x = state->crtc_x;
dst_y = state->crtc_y; dst_y = state->crtc_y;
...@@ -427,14 +517,6 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, ...@@ -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_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); 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); list = sti_gdp_get_free_nodes(gdp);
top_field = list->top_field; top_field = list->top_field;
btm_field = list->btm_field; btm_field = list->btm_field;
...@@ -446,20 +528,11 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, ...@@ -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_agc = GAM_GDP_AGC_FULL_RANGE;
top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
format = sti_gdp_fourcc2format(fb->pixel_format); 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 |= format;
top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format); top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE; top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 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, DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
(char *)&fb->pixel_format, (char *)&fb->pixel_format,
...@@ -496,47 +569,6 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, ...@@ -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 + btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
fb->pitches[0]; 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 /* 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 * (being used by the HW) with the address of the updated ('free') top
* field GDP node. * field GDP node.
...@@ -592,7 +624,6 @@ static void sti_gdp_atomic_disable(struct drm_plane *drm_plane, ...@@ -592,7 +624,6 @@ static void sti_gdp_atomic_disable(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate) struct drm_plane_state *oldstate)
{ {
struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_plane *plane = to_sti_plane(drm_plane);
struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
if (!drm_plane->crtc) { if (!drm_plane->crtc) {
DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
...@@ -601,13 +632,15 @@ static void sti_gdp_atomic_disable(struct drm_plane *drm_plane, ...@@ -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_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)); drm_plane->base.id, sti_plane_to_str(plane));
plane->status = STI_PLANE_DISABLING; plane->status = STI_PLANE_DISABLING;
} }
static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = { static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = {
.atomic_check = sti_gdp_atomic_check,
.atomic_update = sti_gdp_atomic_update, .atomic_update = sti_gdp_atomic_update,
.atomic_disable = sti_gdp_atomic_disable, .atomic_disable = sti_gdp_atomic_disable,
}; };
......
...@@ -4,14 +4,11 @@ ...@@ -4,14 +4,11 @@
* License terms: GNU General Public License (GPL), version 2 * License terms: GNU General Public License (GPL), version 2
*/ */
#include <linux/clk.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <drm/drmP.h> #include <drm/drm_atomic.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
...@@ -670,7 +667,7 @@ static void sti_hqvdp_start_xp70(struct sti_hqvdp *hqvdp) ...@@ -670,7 +667,7 @@ static void sti_hqvdp_start_xp70(struct sti_hqvdp *hqvdp)
DRM_DEBUG_DRIVER("\n"); DRM_DEBUG_DRIVER("\n");
if (hqvdp->xp70_initialized) { if (hqvdp->xp70_initialized) {
DRM_INFO("HQVDP XP70 already initialized\n"); DRM_DEBUG_DRIVER("HQVDP XP70 already initialized\n");
return; return;
} }
...@@ -775,39 +772,124 @@ static void sti_hqvdp_start_xp70(struct sti_hqvdp *hqvdp) ...@@ -775,39 +772,124 @@ static void sti_hqvdp_start_xp70(struct sti_hqvdp *hqvdp)
release_firmware(firmware); release_firmware(firmware);
} }
static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, static int sti_hqvdp_atomic_check(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate) struct drm_plane_state *state)
{ {
struct drm_plane_state *state = drm_plane->state;
struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_plane *plane = to_sti_plane(drm_plane);
struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
struct drm_crtc *crtc = state->crtc; struct drm_crtc *crtc = state->crtc;
struct sti_mixer *mixer = to_sti_mixer(crtc);
struct drm_framebuffer *fb = state->fb; 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; bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
struct drm_gem_cma_object *cma_obj; struct drm_crtc_state *crtc_state;
struct sti_hqvdp_cmd *cmd; struct drm_display_mode *mode;
int scale_h, scale_v; int dst_x, dst_y, dst_w, dst_h;
int cmd_offset; 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", 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_plane->base.id, sti_plane_to_str(plane));
DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
sti_plane_to_str(plane), sti_plane_to_str(plane),
dst_w, dst_h, dst_x, dst_y, dst_w, dst_h, dst_x, dst_y,
src_w, src_h, src_x, src_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); cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
if (cmd_offset == -1) { if (cmd_offset == -1) {
DRM_DEBUG_DRIVER("Warning: no cmd, will skip frame\n"); 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, ...@@ -815,13 +897,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
} }
cmd = hqvdp->hqvdp_cmd + cmd_offset; 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 */ /* Static parameters, defaulting to progressive mode */
cmd->top.config = TOP_CONFIG_PROGRESSIVE; cmd->top.config = TOP_CONFIG_PROGRESSIVE;
cmd->top.mem_format = TOP_MEM_FORMAT_DFLT; cmd->top.mem_format = TOP_MEM_FORMAT_DFLT;
...@@ -836,10 +911,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, ...@@ -836,10 +911,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT; cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT;
cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 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, DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
(char *)&fb->pixel_format, (char *)&fb->pixel_format,
...@@ -860,16 +931,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, ...@@ -860,16 +931,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
dst_w = ALIGN(dst_w, 2); dst_w = ALIGN(dst_w, 2);
dst_h = ALIGN(dst_h, 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_viewport_size = src_h << 16 | src_w;
cmd->top.input_frame_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; 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, ...@@ -900,25 +961,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
scale_v = SCALE_FACTOR * dst_h / src_h; scale_v = SCALE_FACTOR * dst_h / src_h;
sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc); 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, writel(hqvdp->hqvdp_cmd_paddr + cmd_offset,
hqvdp->regs + HQVDP_MBX_NEXT_CMD); hqvdp->regs + HQVDP_MBX_NEXT_CMD);
...@@ -938,7 +980,6 @@ static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane, ...@@ -938,7 +980,6 @@ static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate) struct drm_plane_state *oldstate)
{ {
struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_plane *plane = to_sti_plane(drm_plane);
struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
if (!drm_plane->crtc) { if (!drm_plane->crtc) {
DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
...@@ -947,13 +988,15 @@ static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane, ...@@ -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_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)); drm_plane->base.id, sti_plane_to_str(plane));
plane->status = STI_PLANE_DISABLING; plane->status = STI_PLANE_DISABLING;
} }
static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = { static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = {
.atomic_check = sti_hqvdp_atomic_check,
.atomic_update = sti_hqvdp_atomic_update, .atomic_update = sti_hqvdp_atomic_update,
.atomic_disable = sti_hqvdp_atomic_disable, .atomic_disable = sti_hqvdp_atomic_disable,
}; };
......
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