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

Commit 6134148f authored by Laurent Pinchart's avatar Laurent Pinchart
Browse files

v4l: vsp1: Add support for the BRS entity



The Blend/ROP Sub Unit (BRS) is a stripped-down version of the BRU found
in several VSP2 instances. Compared to a regular BRU, it supports two
inputs only, and thus has no ROP unit.

Add support for the BRS by modelling it as a new entity type, but reuse
the vsp1_bru object underneath. Chaining the BRU and BRS entities seems
to be supported by the hardware but isn't implemented yet as it isn't
the primary use case for the BRS.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: default avatarKieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Acked-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent cebd8c53
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ struct vsp1_uds;
#define VSP1_HAS_WPF_HFLIP	(1 << 6)
#define VSP1_HAS_HGO		(1 << 7)
#define VSP1_HAS_HGT		(1 << 8)
#define VSP1_HAS_BRS		(1 << 9)

struct vsp1_device_info {
	u32 version;
@@ -76,6 +77,7 @@ struct vsp1_device {
	struct rcar_fcp_device *fcp;
	struct device *bus_master;

	struct vsp1_bru *brs;
	struct vsp1_bru *bru;
	struct vsp1_clu *clu;
	struct vsp1_hgo *hgo;
+30 −15
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
static inline void vsp1_bru_write(struct vsp1_bru *bru, struct vsp1_dl_list *dl,
				  u32 reg, u32 data)
{
	vsp1_dl_list_write(dl, reg, data);
	vsp1_dl_list_write(dl, bru->base + reg, data);
}

/* -----------------------------------------------------------------------------
@@ -332,9 +332,12 @@ static void bru_configure(struct vsp1_entity *entity,
	/*
	 * 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.
	 * Blend/ROP unit B SRC input. Only needed for BRU, the BRS has no ROP
	 * unit.
	 */
	vsp1_bru_write(bru, dl, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
	if (entity->type == VSP1_ENTITY_BRU)
		vsp1_bru_write(bru, dl, VI6_BRU_ROP,
			       VI6_BRU_ROP_DSTSEL_BRUIN(1) |
			       VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
			       VI6_BRU_ROP_AROP(VI6_ROP_NOP));

@@ -366,12 +369,13 @@ static void bru_configure(struct vsp1_entity *entity,
			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.
		 * Route inputs 0 to 3 as SRC inputs to Blend/ROP units A to D
		 * in that order. In the BRU the Blend/ROP unit B SRC is
		 * hardwired to the ROP unit output, the corresponding register
		 * bits must be set to 0. The BRS has no ROP unit and doesn't
		 * need any special processing.
		 */
		if (i != 1)
		if (!(entity->type == VSP1_ENTITY_BRU && i == 1))
			ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);

		vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl);
@@ -407,20 +411,31 @@ static const struct vsp1_entity_operations bru_entity_ops = {
 * Initialization and Cleanup
 */

struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1,
				 enum vsp1_entity_type type)
{
	struct vsp1_bru *bru;
	unsigned int num_pads;
	const char *name;
	int ret;

	bru = devm_kzalloc(vsp1->dev, sizeof(*bru), GFP_KERNEL);
	if (bru == NULL)
		return ERR_PTR(-ENOMEM);

	bru->base = type == VSP1_ENTITY_BRU ? VI6_BRU_BASE : VI6_BRS_BASE;
	bru->entity.ops = &bru_entity_ops;
	bru->entity.type = VSP1_ENTITY_BRU;
	bru->entity.type = type;

	ret = vsp1_entity_init(vsp1, &bru->entity, "bru",
			       vsp1->info->num_bru_inputs + 1, &bru_ops,
	if (type == VSP1_ENTITY_BRU) {
		num_pads = vsp1->info->num_bru_inputs + 1;
		name = "bru";
	} else {
		num_pads = 3;
		name = "brs";
	}

	ret = vsp1_entity_init(vsp1, &bru->entity, name, num_pads, &bru_ops,
			       MEDIA_ENT_F_PROC_VIDEO_COMPOSER);
	if (ret < 0)
		return ERR_PTR(ret);
@@ -435,7 +450,7 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
	bru->entity.subdev.ctrl_handler = &bru->ctrls;

	if (bru->ctrls.error) {
		dev_err(vsp1->dev, "bru: failed to initialize controls\n");
		dev_err(vsp1->dev, "%s: failed to initialize controls\n", name);
		ret = bru->ctrls.error;
		vsp1_entity_destroy(&bru->entity);
		return ERR_PTR(ret);
+3 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ struct vsp1_rwpf;

struct vsp1_bru {
	struct vsp1_entity entity;
	unsigned int base;

	struct v4l2_ctrl_handler ctrls;

@@ -41,6 +42,7 @@ static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev)
	return container_of(subdev, struct vsp1_bru, entity.subdev);
}

struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1);
struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1,
				 enum vsp1_entity_type type);

#endif /* __VSP1_BRU_H__ */
+6 −6
Original line number Diff line number Diff line
@@ -62,17 +62,17 @@ EXPORT_SYMBOL_GPL(vsp1_du_init);
 * @cfg: the LIF configuration
 *
 * Configure the output part of VSP DRM pipeline for the given frame @cfg.width
 * and @cfg.height. This sets up formats on the BRU source pad, the WPF0 sink
 * and source pads, and the LIF sink pad.
 * and @cfg.height. This sets up formats on the blend unit (BRU or BRS) source
 * pad, the WPF sink and source pads, and the LIF sink pad.
 *
 * The @pipe_index argument selects which DRM pipeline to setup. The number of
 * available pipelines depend on the VSP instance.
 *
 * As the media bus code on the BRU source pad is conditioned by the
 * configuration of the BRU sink 0 pad, we also set up the formats on all BRU
 * As the media bus code on the blend unit source pad is conditioned by the
 * configuration of its sink 0 pad, we also set up the formats on all blend unit
 * sinks, even if the configuration will be overwritten later by
 * vsp1_du_setup_rpf(). This ensures that the BRU configuration is set to a well
 * defined state.
 * vsp1_du_setup_rpf(). This ensures that the blend unit configuration is set to
 * a well defined state.
 *
 * Return 0 on success or a negative error code on failure.
 */
+18 −1
Original line number Diff line number Diff line
@@ -84,6 +84,10 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
 *
 * - from a UDS to a UDS (UDS entities can't be chained)
 * - from an entity to itself (no loops are allowed)
 *
 * Furthermore, the BRS can't be connected to histogram generators, but no
 * special check is currently needed as all VSP instances that include a BRS
 * have no histogram generator.
 */
static int vsp1_create_sink_links(struct vsp1_device *vsp1,
				  struct vsp1_entity *sink)
@@ -261,8 +265,18 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
	}

	/* Instantiate all the entities. */
	if (vsp1->info->features & VSP1_HAS_BRS) {
		vsp1->brs = vsp1_bru_create(vsp1, VSP1_ENTITY_BRS);
		if (IS_ERR(vsp1->brs)) {
			ret = PTR_ERR(vsp1->brs);
			goto done;
		}

		list_add_tail(&vsp1->brs->entity.list_dev, &vsp1->entities);
	}

	if (vsp1->info->features & VSP1_HAS_BRU) {
		vsp1->bru = vsp1_bru_create(vsp1);
		vsp1->bru = vsp1_bru_create(vsp1, VSP1_ENTITY_BRU);
		if (IS_ERR(vsp1->bru)) {
			ret = PTR_ERR(vsp1->bru);
			goto done;
@@ -502,6 +516,9 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
	vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED);
	vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED);

	if (vsp1->info->features & VSP1_HAS_BRS)
		vsp1_write(vsp1, VI6_DPR_ILV_BRS_ROUTE, VI6_DPR_NODE_UNUSED);

	vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
	vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
Loading