forked from luck/tmp_suning_uos_patched
media: drm: rcar-du: Add support for CRC computation
Implement CRC computation configuration and reporting through the DRM debugfs-based CRC API. The CRC source can be configured to any input plane or the pipeline output. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
parent
5e824f989e
commit
47a52d024e
|
@ -691,6 +691,52 @@ static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
|
||||||
.atomic_disable = rcar_du_crtc_atomic_disable,
|
.atomic_disable = rcar_du_crtc_atomic_disable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct drm_crtc_state *
|
||||||
|
rcar_du_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct rcar_du_crtc_state *state;
|
||||||
|
struct rcar_du_crtc_state *copy;
|
||||||
|
|
||||||
|
if (WARN_ON(!crtc->state))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
state = to_rcar_crtc_state(crtc->state);
|
||||||
|
copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
|
||||||
|
if (copy == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
__drm_atomic_helper_crtc_duplicate_state(crtc, ©->state);
|
||||||
|
|
||||||
|
return ©->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rcar_du_crtc_atomic_destroy_state(struct drm_crtc *crtc,
|
||||||
|
struct drm_crtc_state *state)
|
||||||
|
{
|
||||||
|
__drm_atomic_helper_crtc_destroy_state(state);
|
||||||
|
kfree(to_rcar_crtc_state(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rcar_du_crtc_reset(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct rcar_du_crtc_state *state;
|
||||||
|
|
||||||
|
if (crtc->state) {
|
||||||
|
rcar_du_crtc_atomic_destroy_state(crtc, crtc->state);
|
||||||
|
crtc->state = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||||
|
if (state == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
state->crc.source = VSP1_DU_CRC_NONE;
|
||||||
|
state->crc.index = 0;
|
||||||
|
|
||||||
|
crtc->state = &state->state;
|
||||||
|
crtc->state->crtc = crtc;
|
||||||
|
}
|
||||||
|
|
||||||
static int rcar_du_crtc_enable_vblank(struct drm_crtc *crtc)
|
static int rcar_du_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
|
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
|
||||||
|
@ -710,17 +756,113 @@ static void rcar_du_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||||
rcrtc->vblank_enable = false;
|
rcrtc->vblank_enable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct drm_crtc_funcs crtc_funcs = {
|
static int rcar_du_crtc_set_crc_source(struct drm_crtc *crtc,
|
||||||
.reset = drm_atomic_helper_crtc_reset,
|
const char *source_name,
|
||||||
|
size_t *values_cnt)
|
||||||
|
{
|
||||||
|
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
|
||||||
|
struct drm_modeset_acquire_ctx ctx;
|
||||||
|
struct drm_crtc_state *crtc_state;
|
||||||
|
struct drm_atomic_state *state;
|
||||||
|
enum vsp1_du_crc_source source;
|
||||||
|
unsigned int index = 0;
|
||||||
|
unsigned int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the source name. Supported values are "plane%u" to compute the
|
||||||
|
* CRC on an input plane (%u is the plane ID), and "auto" to compute the
|
||||||
|
* CRC on the composer (VSP) output.
|
||||||
|
*/
|
||||||
|
if (!source_name) {
|
||||||
|
source = VSP1_DU_CRC_NONE;
|
||||||
|
} else if (!strcmp(source_name, "auto")) {
|
||||||
|
source = VSP1_DU_CRC_OUTPUT;
|
||||||
|
} else if (strstarts(source_name, "plane")) {
|
||||||
|
source = VSP1_DU_CRC_PLANE;
|
||||||
|
|
||||||
|
ret = kstrtouint(source_name + strlen("plane"), 10, &index);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i = 0; i < rcrtc->vsp->num_planes; ++i) {
|
||||||
|
if (index == rcrtc->vsp->planes[i].plane.base.id) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= rcrtc->vsp->num_planes)
|
||||||
|
return -EINVAL;
|
||||||
|
} else {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*values_cnt = 1;
|
||||||
|
|
||||||
|
/* Perform an atomic commit to set the CRC source. */
|
||||||
|
drm_modeset_acquire_init(&ctx, 0);
|
||||||
|
|
||||||
|
state = drm_atomic_state_alloc(crtc->dev);
|
||||||
|
if (!state) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->acquire_ctx = &ctx;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
||||||
|
if (!IS_ERR(crtc_state)) {
|
||||||
|
struct rcar_du_crtc_state *rcrtc_state;
|
||||||
|
|
||||||
|
rcrtc_state = to_rcar_crtc_state(crtc_state);
|
||||||
|
rcrtc_state->crc.source = source;
|
||||||
|
rcrtc_state->crc.index = index;
|
||||||
|
|
||||||
|
ret = drm_atomic_commit(state);
|
||||||
|
} else {
|
||||||
|
ret = PTR_ERR(crtc_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == -EDEADLK) {
|
||||||
|
drm_atomic_state_clear(state);
|
||||||
|
drm_modeset_backoff(&ctx);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_atomic_state_put(state);
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
drm_modeset_drop_locks(&ctx);
|
||||||
|
drm_modeset_acquire_fini(&ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_crtc_funcs crtc_funcs_gen2 = {
|
||||||
|
.reset = rcar_du_crtc_reset,
|
||||||
.destroy = drm_crtc_cleanup,
|
.destroy = drm_crtc_cleanup,
|
||||||
.set_config = drm_atomic_helper_set_config,
|
.set_config = drm_atomic_helper_set_config,
|
||||||
.page_flip = drm_atomic_helper_page_flip,
|
.page_flip = drm_atomic_helper_page_flip,
|
||||||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
.atomic_duplicate_state = rcar_du_crtc_atomic_duplicate_state,
|
||||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
.atomic_destroy_state = rcar_du_crtc_atomic_destroy_state,
|
||||||
.enable_vblank = rcar_du_crtc_enable_vblank,
|
.enable_vblank = rcar_du_crtc_enable_vblank,
|
||||||
.disable_vblank = rcar_du_crtc_disable_vblank,
|
.disable_vblank = rcar_du_crtc_disable_vblank,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct drm_crtc_funcs crtc_funcs_gen3 = {
|
||||||
|
.reset = rcar_du_crtc_reset,
|
||||||
|
.destroy = drm_crtc_cleanup,
|
||||||
|
.set_config = drm_atomic_helper_set_config,
|
||||||
|
.page_flip = drm_atomic_helper_page_flip,
|
||||||
|
.atomic_duplicate_state = rcar_du_crtc_atomic_duplicate_state,
|
||||||
|
.atomic_destroy_state = rcar_du_crtc_atomic_destroy_state,
|
||||||
|
.enable_vblank = rcar_du_crtc_enable_vblank,
|
||||||
|
.disable_vblank = rcar_du_crtc_disable_vblank,
|
||||||
|
.set_crc_source = rcar_du_crtc_set_crc_source,
|
||||||
|
};
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
* Interrupt Handling
|
* Interrupt Handling
|
||||||
*/
|
*/
|
||||||
|
@ -821,8 +963,10 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
|
||||||
else
|
else
|
||||||
primary = &rgrp->planes[index % 2].plane;
|
primary = &rgrp->planes[index % 2].plane;
|
||||||
|
|
||||||
ret = drm_crtc_init_with_planes(rcdu->ddev, crtc, primary,
|
ret = drm_crtc_init_with_planes(rcdu->ddev, crtc, primary, NULL,
|
||||||
NULL, &crtc_funcs, NULL);
|
rcdu->info->gen <= 2 ?
|
||||||
|
&crtc_funcs_gen2 : &crtc_funcs_gen3,
|
||||||
|
NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include <drm/drmP.h>
|
#include <drm/drmP.h>
|
||||||
#include <drm/drm_crtc.h>
|
#include <drm/drm_crtc.h>
|
||||||
|
|
||||||
|
#include <media/vsp1.h>
|
||||||
|
|
||||||
struct rcar_du_group;
|
struct rcar_du_group;
|
||||||
struct rcar_du_vsp;
|
struct rcar_du_vsp;
|
||||||
|
|
||||||
|
@ -69,6 +71,19 @@ struct rcar_du_crtc {
|
||||||
|
|
||||||
#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc)
|
#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rcar_du_crtc_state - Driver-specific CRTC state
|
||||||
|
* @state: base DRM CRTC state
|
||||||
|
* @crc: CRC computation configuration
|
||||||
|
*/
|
||||||
|
struct rcar_du_crtc_state {
|
||||||
|
struct drm_crtc_state state;
|
||||||
|
|
||||||
|
struct vsp1_du_crc_config crc;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_rcar_crtc_state(s) container_of(s, struct rcar_du_crtc_state, state)
|
||||||
|
|
||||||
enum rcar_du_output {
|
enum rcar_du_output {
|
||||||
RCAR_DU_OUTPUT_DPAD0,
|
RCAR_DU_OUTPUT_DPAD0,
|
||||||
RCAR_DU_OUTPUT_DPAD1,
|
RCAR_DU_OUTPUT_DPAD1,
|
||||||
|
|
|
@ -40,6 +40,8 @@ static void rcar_du_vsp_complete(void *private, bool completed, u32 crc)
|
||||||
|
|
||||||
if (completed)
|
if (completed)
|
||||||
rcar_du_crtc_finish_page_flip(crtc);
|
rcar_du_crtc_finish_page_flip(crtc);
|
||||||
|
|
||||||
|
drm_crtc_add_crc_entry(&crtc->crtc, false, 0, &crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
|
void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
|
||||||
|
@ -103,6 +105,10 @@ void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc)
|
||||||
void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc)
|
void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct vsp1_du_atomic_pipe_config cfg = { { 0, } };
|
struct vsp1_du_atomic_pipe_config cfg = { { 0, } };
|
||||||
|
struct rcar_du_crtc_state *state;
|
||||||
|
|
||||||
|
state = to_rcar_crtc_state(crtc->crtc.state);
|
||||||
|
cfg.crc = state->crc;
|
||||||
|
|
||||||
vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe, &cfg);
|
vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe, &cfg);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user