Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b905f05 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

[media] v4l: vsp1: Create a new configure operation to setup modules



The subdev s_stream operation is abused as a generic way to setup
modules at every frame. Move the code out to a new VSP1 entity configure
operation.

Most modules now have an empty s_stream operation that can be removed.
The only exception is the WPF module that needs to perform hardware
configuration when stopping the stream. The code can be simplified
accordingly as we know that that operation never fails.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent b7e5107e
Loading
Loading
Loading
Loading
+111 −120
Original line number Diff line number Diff line
@@ -56,117 +56,7 @@ static const struct v4l2_ctrl_ops bru_ctrl_ops = {
};

/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Core Operations
 */

static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
{
	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
	struct vsp1_bru *bru = to_bru(subdev);
	struct v4l2_mbus_framefmt *format;
	unsigned int flags;
	unsigned int i;

	if (!enable)
		return 0;

	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
					    bru->entity.source_pad);

	/* The hardware is extremely flexible but we have no userspace API to
	 * expose all the parameters, nor is it clear whether we would have use
	 * cases for all the supported modes. Let's just harcode the parameters
	 * to sane default values for now.
	 */

	/* Disable dithering and enable color data normalization unless the
	 * format at the pipeline output is premultiplied.
	 */
	flags = pipe->output ? pipe->output->format.flags : 0;
	vsp1_bru_write(bru, VI6_BRU_INCTRL,
		       flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
		       0 : VI6_BRU_INCTRL_NRM);

	/* Set the background position to cover the whole output image and
	 * configure its color.
	 */
	vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
		       (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
		       (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
	vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);

	vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, bru->bgcolor |
		       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));

	/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
	 * unit with a NOP operation to make BRU input 1 available as the
	 * Blend/ROP unit B SRC input.
	 */
	vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
		       VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
		       VI6_BRU_ROP_AROP(VI6_ROP_NOP));

	for (i = 0; i < bru->entity.source_pad; ++i) {
		bool premultiplied = false;
		u32 ctrl = 0;

		/* Configure all Blend/ROP units corresponding to an enabled BRU
		 * input for alpha blending. Blend/ROP units corresponding to
		 * disabled BRU inputs are used in ROP NOP mode to ignore the
		 * SRC input.
		 */
		if (bru->inputs[i].rpf) {
			ctrl |= VI6_BRU_CTRL_RBC;

			premultiplied = bru->inputs[i].rpf->format.flags
				      & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
		} else {
			ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
			     |  VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
		}

		/* Select the virtual RPF as the Blend/ROP unit A DST input to
		 * serve as a background color.
		 */
		if (i == 0)
			ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;

		/* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
		 * D in that order. The Blend/ROP unit B SRC is hardwired to the
		 * ROP unit output, the corresponding register bits must be set
		 * to 0.
		 */
		if (i != 1)
			ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);

		vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);

		/* Harcode the blending formula to
		 *
		 *	DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
		 *	DSTa = DSTa * (1 - SRCa) + SRCa
		 *
		 * when the SRC input isn't premultiplied, and to
		 *
		 *	DSTc = DSTc * (1 - SRCa) + SRCc
		 *	DSTa = DSTa * (1 - SRCa) + SRCa
		 *
		 * otherwise.
		 */
		vsp1_bru_write(bru, VI6_BRU_BLD(i),
			       VI6_BRU_BLD_CCMDX_255_SRC_A |
			       (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
						VI6_BRU_BLD_CCMDY_SRC_A) |
			       VI6_BRU_BLD_ACMDX_255_SRC_A |
			       VI6_BRU_BLD_ACMDY_COEFY |
			       (0xff << VI6_BRU_BLD_COEFY_SHIFT));
	}

	return 0;
}

/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Pad Operations
 * V4L2 Subdevice Operations
 */

/*
@@ -395,14 +285,6 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
	return 0;
}

/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Operations
 */

static struct v4l2_subdev_video_ops bru_video_ops = {
	.s_stream = bru_s_stream,
};

static struct v4l2_subdev_pad_ops bru_pad_ops = {
	.init_cfg = vsp1_entity_init_cfg,
	.enum_mbus_code = bru_enum_mbus_code,
@@ -414,10 +296,118 @@ static struct v4l2_subdev_pad_ops bru_pad_ops = {
};

static struct v4l2_subdev_ops bru_ops = {
	.video	= &bru_video_ops,
	.pad    = &bru_pad_ops,
};

/* -----------------------------------------------------------------------------
 * VSP1 Entity Operations
 */

static void bru_configure(struct vsp1_entity *entity)
{
	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
	struct vsp1_bru *bru = to_bru(&entity->subdev);
	struct v4l2_mbus_framefmt *format;
	unsigned int flags;
	unsigned int i;

	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
					    bru->entity.source_pad);

	/* The hardware is extremely flexible but we have no userspace API to
	 * expose all the parameters, nor is it clear whether we would have use
	 * cases for all the supported modes. Let's just harcode the parameters
	 * to sane default values for now.
	 */

	/* Disable dithering and enable color data normalization unless the
	 * format at the pipeline output is premultiplied.
	 */
	flags = pipe->output ? pipe->output->format.flags : 0;
	vsp1_bru_write(bru, VI6_BRU_INCTRL,
		       flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
		       0 : VI6_BRU_INCTRL_NRM);

	/* Set the background position to cover the whole output image and
	 * configure its color.
	 */
	vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
		       (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
		       (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
	vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);

	vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, bru->bgcolor |
		       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));

	/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
	 * unit with a NOP operation to make BRU input 1 available as the
	 * Blend/ROP unit B SRC input.
	 */
	vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
		       VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
		       VI6_BRU_ROP_AROP(VI6_ROP_NOP));

	for (i = 0; i < bru->entity.source_pad; ++i) {
		bool premultiplied = false;
		u32 ctrl = 0;

		/* Configure all Blend/ROP units corresponding to an enabled BRU
		 * input for alpha blending. Blend/ROP units corresponding to
		 * disabled BRU inputs are used in ROP NOP mode to ignore the
		 * SRC input.
		 */
		if (bru->inputs[i].rpf) {
			ctrl |= VI6_BRU_CTRL_RBC;

			premultiplied = bru->inputs[i].rpf->format.flags
				      & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
		} else {
			ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
			     |  VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
		}

		/* Select the virtual RPF as the Blend/ROP unit A DST input to
		 * serve as a background color.
		 */
		if (i == 0)
			ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;

		/* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
		 * D in that order. The Blend/ROP unit B SRC is hardwired to the
		 * ROP unit output, the corresponding register bits must be set
		 * to 0.
		 */
		if (i != 1)
			ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);

		vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);

		/* Harcode the blending formula to
		 *
		 *	DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
		 *	DSTa = DSTa * (1 - SRCa) + SRCa
		 *
		 * when the SRC input isn't premultiplied, and to
		 *
		 *	DSTc = DSTc * (1 - SRCa) + SRCc
		 *	DSTa = DSTa * (1 - SRCa) + SRCa
		 *
		 * otherwise.
		 */
		vsp1_bru_write(bru, VI6_BRU_BLD(i),
			       VI6_BRU_BLD_CCMDX_255_SRC_A |
			       (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
						VI6_BRU_BLD_CCMDY_SRC_A) |
			       VI6_BRU_BLD_ACMDX_255_SRC_A |
			       VI6_BRU_BLD_ACMDY_COEFY |
			       (0xff << VI6_BRU_BLD_COEFY_SHIFT));
	}
}

static const struct vsp1_entity_operations bru_entity_ops = {
	.configure = bru_configure,
};

/* -----------------------------------------------------------------------------
 * Initialization and Cleanup
 */
@@ -431,6 +421,7 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
	if (bru == NULL)
		return ERR_PTR(-ENOMEM);

	bru->entity.ops = &bru_entity_ops;
	bru->entity.type = VSP1_ENTITY_BRU;

	ret = vsp1_entity_init(vsp1, &bru->entity, "bru",
+5 −9
Original line number Diff line number Diff line
@@ -448,7 +448,6 @@ void vsp1_du_atomic_flush(struct device *dev)
	struct vsp1_entity *entity;
	unsigned long flags;
	bool stop = false;
	int ret;

	list_for_each_entry(entity, &pipe->entities, list_pipe) {
		/* Disconnect unused RPFs from the pipeline. */
@@ -464,19 +463,16 @@ void vsp1_du_atomic_flush(struct device *dev)

		vsp1_entity_route_setup(entity);

		ret = v4l2_subdev_call(&entity->subdev, video,
				       s_stream, 1);
		if (ret < 0) {
			dev_err(vsp1->dev,
				"DRM pipeline start failure on entity %s\n",
				entity->subdev.name);
			return;
		}
		if (entity->ops->configure)
			entity->ops->configure(entity);

		if (entity->type == VSP1_ENTITY_RPF)
			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev));
	}

	/* We know that the WPF s_stream operation never fails. */
	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 1);

	vsp1_dl_list_commit(pipe->dl);
	pipe->dl = NULL;

+3 −0
Original line number Diff line number Diff line
@@ -59,10 +59,13 @@ struct vsp1_route {
 * @set_memory:	Setup memory buffer access. This operation applies the settings
 *		stored in the rwpf mem field to the hardware. Valid for RPF and
 *		WPF only.
 * @configure:	Setup the hardware based on the entity state (pipeline, formats,
 *		selection rectangles, ...)
 */
struct vsp1_entity_operations {
	void (*destroy)(struct vsp1_entity *);
	void (*set_memory)(struct vsp1_entity *);
	void (*configure)(struct vsp1_entity *);
};

struct vsp1_entity {
+21 −29
Original line number Diff line number Diff line
@@ -32,26 +32,7 @@ static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
}

/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Core Operations
 */

static int hsit_s_stream(struct v4l2_subdev *subdev, int enable)
{
	struct vsp1_hsit *hsit = to_hsit(subdev);

	if (!enable)
		return 0;

	if (hsit->inverse)
		vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
	else
		vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);

	return 0;
}

/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Pad Operations
 * V4L2 Subdevice Operations
 */

static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -167,14 +148,6 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
	return 0;
}

/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Operations
 */

static struct v4l2_subdev_video_ops hsit_video_ops = {
	.s_stream = hsit_s_stream,
};

static struct v4l2_subdev_pad_ops hsit_pad_ops = {
	.init_cfg = vsp1_entity_init_cfg,
	.enum_mbus_code = hsit_enum_mbus_code,
@@ -184,10 +157,27 @@ static struct v4l2_subdev_pad_ops hsit_pad_ops = {
};

static struct v4l2_subdev_ops hsit_ops = {
	.video	= &hsit_video_ops,
	.pad    = &hsit_pad_ops,
};

/* -----------------------------------------------------------------------------
 * VSP1 Entity Operations
 */

static void hsit_configure(struct vsp1_entity *entity)
{
	struct vsp1_hsit *hsit = to_hsit(&entity->subdev);

	if (hsit->inverse)
		vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
	else
		vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);
}

static const struct vsp1_entity_operations hsit_entity_ops = {
	.configure = hsit_configure,
};

/* -----------------------------------------------------------------------------
 * Initialization and Cleanup
 */
@@ -203,6 +193,8 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)

	hsit->inverse = inverse;

	hsit->entity.ops = &hsit_entity_ops;

	if (inverse)
		hsit->entity.type = VSP1_ENTITY_HSI;
	else
+33 −44
Original line number Diff line number Diff line
@@ -32,41 +32,7 @@ static inline void vsp1_lif_write(struct vsp1_lif *lif, u32 reg, u32 data)
}

/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Core Operations
 */

static int lif_s_stream(struct v4l2_subdev *subdev, int enable)
{
	const struct v4l2_mbus_framefmt *format;
	struct vsp1_lif *lif = to_lif(subdev);
	unsigned int hbth = 1300;
	unsigned int obth = 400;
	unsigned int lbth = 200;

	if (!enable) {
		vsp1_write(lif->entity.vsp1, VI6_LIF_CTRL, 0);
		return 0;
	}

	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
					    LIF_PAD_SOURCE);

	obth = min(obth, (format->width + 1) / 2 * format->height - 4);

	vsp1_lif_write(lif, VI6_LIF_CSBTH,
			(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
			(lbth << VI6_LIF_CSBTH_LBTH_SHIFT));

	vsp1_lif_write(lif, VI6_LIF_CTRL,
			(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
			(format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) |
			VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);

	return 0;
}

/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Pad Operations
 * V4L2 Subdevice Operations
 */

static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -201,14 +167,6 @@ static int lif_set_format(struct v4l2_subdev *subdev,
	return 0;
}

/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Operations
 */

static struct v4l2_subdev_video_ops lif_video_ops = {
	.s_stream = lif_s_stream,
};

static struct v4l2_subdev_pad_ops lif_pad_ops = {
	.init_cfg = vsp1_entity_init_cfg,
	.enum_mbus_code = lif_enum_mbus_code,
@@ -218,10 +176,40 @@ static struct v4l2_subdev_pad_ops lif_pad_ops = {
};

static struct v4l2_subdev_ops lif_ops = {
	.video	= &lif_video_ops,
	.pad    = &lif_pad_ops,
};

/* -----------------------------------------------------------------------------
 * VSP1 Entity Operations
 */

static void lif_configure(struct vsp1_entity *entity)
{
	const struct v4l2_mbus_framefmt *format;
	struct vsp1_lif *lif = to_lif(&entity->subdev);
	unsigned int hbth = 1300;
	unsigned int obth = 400;
	unsigned int lbth = 200;

	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
					    LIF_PAD_SOURCE);

	obth = min(obth, (format->width + 1) / 2 * format->height - 4);

	vsp1_lif_write(lif, VI6_LIF_CSBTH,
			(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
			(lbth << VI6_LIF_CSBTH_LBTH_SHIFT));

	vsp1_lif_write(lif, VI6_LIF_CTRL,
			(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
			(format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) |
			VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
}

static const struct vsp1_entity_operations lif_entity_ops = {
	.configure = lif_configure,
};

/* -----------------------------------------------------------------------------
 * Initialization and Cleanup
 */
@@ -235,6 +223,7 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
	if (lif == NULL)
		return ERR_PTR(-ENOMEM);

	lif->entity.ops = &lif_entity_ops;
	lif->entity.type = VSP1_ENTITY_LIF;

	ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops);
Loading