mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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
					
				
					 3 changed files with 171 additions and 6 deletions
				
			
		| 
						 | 
					@ -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 a new issue