xref: /linux/drivers/media/platform/renesas/vsp1/vsp1_lut.c (revision c771600c6af14749609b49565ffb4cac2959710d)
11c4b5f49SLaurent Pinchart // SPDX-License-Identifier: GPL-2.0+
2989af883SLaurent Pinchart /*
3989af883SLaurent Pinchart  * vsp1_lut.c  --  R-Car VSP1 Look-Up Table
4989af883SLaurent Pinchart  *
5989af883SLaurent Pinchart  * Copyright (C) 2013 Renesas Corporation
6989af883SLaurent Pinchart  *
7989af883SLaurent Pinchart  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8989af883SLaurent Pinchart  */
9989af883SLaurent Pinchart 
10989af883SLaurent Pinchart #include <linux/device.h>
11989af883SLaurent Pinchart #include <linux/gfp.h>
12989af883SLaurent Pinchart 
13989af883SLaurent Pinchart #include <media/v4l2-subdev.h>
14989af883SLaurent Pinchart 
15989af883SLaurent Pinchart #include "vsp1.h"
165e8dbbf3SLaurent Pinchart #include "vsp1_dl.h"
17989af883SLaurent Pinchart #include "vsp1_lut.h"
18989af883SLaurent Pinchart 
19989af883SLaurent Pinchart #define LUT_MIN_SIZE				4U
20989af883SLaurent Pinchart #define LUT_MAX_SIZE				8190U
21989af883SLaurent Pinchart 
225d7936b8SKieran Bingham #define LUT_SIZE				256
235d7936b8SKieran Bingham 
24989af883SLaurent Pinchart /* -----------------------------------------------------------------------------
25989af883SLaurent Pinchart  * Device Access
26989af883SLaurent Pinchart  */
27989af883SLaurent Pinchart 
vsp1_lut_write(struct vsp1_lut * lut,struct vsp1_dl_body * dlb,u32 reg,u32 data)2812832dd9SKieran Bingham static inline void vsp1_lut_write(struct vsp1_lut *lut,
2912832dd9SKieran Bingham 				  struct vsp1_dl_body *dlb, u32 reg, u32 data)
30989af883SLaurent Pinchart {
3112832dd9SKieran Bingham 	vsp1_dl_body_write(dlb, reg, data);
32989af883SLaurent Pinchart }
33989af883SLaurent Pinchart 
34989af883SLaurent Pinchart /* -----------------------------------------------------------------------------
3542e89bedSLaurent Pinchart  * Controls
36989af883SLaurent Pinchart  */
37989af883SLaurent Pinchart 
3842e89bedSLaurent Pinchart #define V4L2_CID_VSP1_LUT_TABLE			(V4L2_CID_USER_BASE | 0x1001)
3942e89bedSLaurent Pinchart 
lut_set_table(struct vsp1_lut * lut,struct v4l2_ctrl * ctrl)4042e89bedSLaurent Pinchart static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl)
41989af883SLaurent Pinchart {
420e6b9c56SLaurent Pinchart 	struct vsp1_dl_body *dlb;
430e6b9c56SLaurent Pinchart 	unsigned int i;
440e6b9c56SLaurent Pinchart 
455d7936b8SKieran Bingham 	dlb = vsp1_dl_body_get(lut->pool);
460e6b9c56SLaurent Pinchart 	if (!dlb)
470e6b9c56SLaurent Pinchart 		return -ENOMEM;
480e6b9c56SLaurent Pinchart 
495d7936b8SKieran Bingham 	for (i = 0; i < LUT_SIZE; ++i)
50764dfee1SKieran Bingham 		vsp1_dl_body_write(dlb, VI6_LUT_TABLE + 4 * i,
5142e89bedSLaurent Pinchart 				       ctrl->p_new.p_u32[i]);
520e6b9c56SLaurent Pinchart 
53f4e37fb7SLaurent Pinchart 	spin_lock_irq(&lut->lock);
540e6b9c56SLaurent Pinchart 	swap(lut->lut, dlb);
55f4e37fb7SLaurent Pinchart 	spin_unlock_irq(&lut->lock);
560e6b9c56SLaurent Pinchart 
575d7936b8SKieran Bingham 	vsp1_dl_body_put(dlb);
580e6b9c56SLaurent Pinchart 	return 0;
59989af883SLaurent Pinchart }
60989af883SLaurent Pinchart 
lut_s_ctrl(struct v4l2_ctrl * ctrl)6142e89bedSLaurent Pinchart static int lut_s_ctrl(struct v4l2_ctrl *ctrl)
62989af883SLaurent Pinchart {
6342e89bedSLaurent Pinchart 	struct vsp1_lut *lut =
6442e89bedSLaurent Pinchart 		container_of(ctrl->handler, struct vsp1_lut, ctrls);
65989af883SLaurent Pinchart 
6642e89bedSLaurent Pinchart 	switch (ctrl->id) {
6742e89bedSLaurent Pinchart 	case V4L2_CID_VSP1_LUT_TABLE:
6842e89bedSLaurent Pinchart 		lut_set_table(lut, ctrl);
6942e89bedSLaurent Pinchart 		break;
7042e89bedSLaurent Pinchart 	}
71989af883SLaurent Pinchart 
7242e89bedSLaurent Pinchart 	return 0;
73989af883SLaurent Pinchart }
7442e89bedSLaurent Pinchart 
7542e89bedSLaurent Pinchart static const struct v4l2_ctrl_ops lut_ctrl_ops = {
7642e89bedSLaurent Pinchart 	.s_ctrl = lut_s_ctrl,
7742e89bedSLaurent Pinchart };
7842e89bedSLaurent Pinchart 
7942e89bedSLaurent Pinchart static const struct v4l2_ctrl_config lut_table_control = {
8042e89bedSLaurent Pinchart 	.ops = &lut_ctrl_ops,
8142e89bedSLaurent Pinchart 	.id = V4L2_CID_VSP1_LUT_TABLE,
8242e89bedSLaurent Pinchart 	.name = "Look-Up Table",
8342e89bedSLaurent Pinchart 	.type = V4L2_CTRL_TYPE_U32,
8442e89bedSLaurent Pinchart 	.min = 0x00000000,
8542e89bedSLaurent Pinchart 	.max = 0x00ffffff,
8642e89bedSLaurent Pinchart 	.step = 1,
8742e89bedSLaurent Pinchart 	.def = 0,
885d7936b8SKieran Bingham 	.dims = { LUT_SIZE },
8942e89bedSLaurent Pinchart };
90989af883SLaurent Pinchart 
91989af883SLaurent Pinchart /* -----------------------------------------------------------------------------
92989af883SLaurent Pinchart  * V4L2 Subdevice Pad Operations
93989af883SLaurent Pinchart  */
94989af883SLaurent Pinchart 
95b4ccae10SLaurent Pinchart static const unsigned int lut_codes[] = {
9627ffaeb0SBoris BREZILLON 	MEDIA_BUS_FMT_ARGB8888_1X32,
9727ffaeb0SBoris BREZILLON 	MEDIA_BUS_FMT_AHSV8888_1X32,
9827ffaeb0SBoris BREZILLON 	MEDIA_BUS_FMT_AYUV8_1X32,
99989af883SLaurent Pinchart };
100989af883SLaurent Pinchart 
lut_enum_mbus_code(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)101b4ccae10SLaurent Pinchart static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
1020d346d2aSTomi Valkeinen 			      struct v4l2_subdev_state *sd_state,
103b4ccae10SLaurent Pinchart 			      struct v4l2_subdev_mbus_code_enum *code)
104b4ccae10SLaurent Pinchart {
1050d346d2aSTomi Valkeinen 	return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, lut_codes,
106b4ccae10SLaurent Pinchart 					  ARRAY_SIZE(lut_codes));
107989af883SLaurent Pinchart }
108989af883SLaurent Pinchart 
lut_enum_frame_size(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)109989af883SLaurent Pinchart static int lut_enum_frame_size(struct v4l2_subdev *subdev,
1100d346d2aSTomi Valkeinen 			       struct v4l2_subdev_state *sd_state,
111989af883SLaurent Pinchart 			       struct v4l2_subdev_frame_size_enum *fse)
112989af883SLaurent Pinchart {
1130d346d2aSTomi Valkeinen 	return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
1140d346d2aSTomi Valkeinen 					   LUT_MIN_SIZE,
115076e834fSLaurent Pinchart 					   LUT_MIN_SIZE, LUT_MAX_SIZE,
116076e834fSLaurent Pinchart 					   LUT_MAX_SIZE);
117989af883SLaurent Pinchart }
118989af883SLaurent Pinchart 
lut_set_format(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)1191bd0a1bdSLaurent Pinchart static int lut_set_format(struct v4l2_subdev *subdev,
1200d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
121989af883SLaurent Pinchart 			  struct v4l2_subdev_format *fmt)
122989af883SLaurent Pinchart {
1230d346d2aSTomi Valkeinen 	return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, lut_codes,
124b4ccae10SLaurent Pinchart 					  ARRAY_SIZE(lut_codes),
125b4ccae10SLaurent Pinchart 					  LUT_MIN_SIZE, LUT_MIN_SIZE,
126b4ccae10SLaurent Pinchart 					  LUT_MAX_SIZE, LUT_MAX_SIZE);
127989af883SLaurent Pinchart }
128989af883SLaurent Pinchart 
129989af883SLaurent Pinchart /* -----------------------------------------------------------------------------
130989af883SLaurent Pinchart  * V4L2 Subdevice Operations
131989af883SLaurent Pinchart  */
132989af883SLaurent Pinchart 
133eb9163d3SLaurent Pinchart static const struct v4l2_subdev_pad_ops lut_pad_ops = {
134989af883SLaurent Pinchart 	.enum_mbus_code = lut_enum_mbus_code,
135989af883SLaurent Pinchart 	.enum_frame_size = lut_enum_frame_size,
1363f557220SLaurent Pinchart 	.get_fmt = vsp1_subdev_get_pad_format,
137989af883SLaurent Pinchart 	.set_fmt = lut_set_format,
138989af883SLaurent Pinchart };
139989af883SLaurent Pinchart 
140eb9163d3SLaurent Pinchart static const struct v4l2_subdev_ops lut_ops = {
141989af883SLaurent Pinchart 	.pad    = &lut_pad_ops,
142989af883SLaurent Pinchart };
143989af883SLaurent Pinchart 
144989af883SLaurent Pinchart /* -----------------------------------------------------------------------------
1457b905f05SLaurent Pinchart  * VSP1 Entity Operations
1467b905f05SLaurent Pinchart  */
1477b905f05SLaurent Pinchart 
lut_configure_stream(struct vsp1_entity * entity,struct v4l2_subdev_state * state,struct vsp1_pipeline * pipe,struct vsp1_dl_list * dl,struct vsp1_dl_body * dlb)14846ce3639SKieran Bingham static void lut_configure_stream(struct vsp1_entity *entity,
1494be710a3SLaurent Pinchart 				 struct v4l2_subdev_state *state,
15083dd019dSLaurent Pinchart 				 struct vsp1_pipeline *pipe,
151b36c6049SLaurent Pinchart 				 struct vsp1_dl_list *dl,
15212832dd9SKieran Bingham 				 struct vsp1_dl_body *dlb)
15346ce3639SKieran Bingham {
15446ce3639SKieran Bingham 	struct vsp1_lut *lut = to_lut(&entity->subdev);
15546ce3639SKieran Bingham 
15612832dd9SKieran Bingham 	vsp1_lut_write(lut, dlb, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
15746ce3639SKieran Bingham }
15846ce3639SKieran Bingham 
lut_configure_frame(struct vsp1_entity * entity,struct vsp1_pipeline * pipe,struct vsp1_dl_list * dl,struct vsp1_dl_body * dlb)15946ce3639SKieran Bingham static void lut_configure_frame(struct vsp1_entity *entity,
16046ce3639SKieran Bingham 				struct vsp1_pipeline *pipe,
16112832dd9SKieran Bingham 				struct vsp1_dl_list *dl,
16212832dd9SKieran Bingham 				struct vsp1_dl_body *dlb)
1637b905f05SLaurent Pinchart {
1647b905f05SLaurent Pinchart 	struct vsp1_lut *lut = to_lut(&entity->subdev);
16512832dd9SKieran Bingham 	struct vsp1_dl_body *lut_dlb;
166f4e37fb7SLaurent Pinchart 	unsigned long flags;
1677b905f05SLaurent Pinchart 
168f4e37fb7SLaurent Pinchart 	spin_lock_irqsave(&lut->lock, flags);
16912832dd9SKieran Bingham 	lut_dlb = lut->lut;
170f4e37fb7SLaurent Pinchart 	lut->lut = NULL;
171f4e37fb7SLaurent Pinchart 	spin_unlock_irqrestore(&lut->lock, flags);
172f4e37fb7SLaurent Pinchart 
17312832dd9SKieran Bingham 	if (lut_dlb) {
17412832dd9SKieran Bingham 		vsp1_dl_list_add_body(dl, lut_dlb);
1752d9445dbSKieran Bingham 
1762d9445dbSKieran Bingham 		/* Release our local reference. */
17712832dd9SKieran Bingham 		vsp1_dl_body_put(lut_dlb);
1782d9445dbSKieran Bingham 	}
1797b905f05SLaurent Pinchart }
1807b905f05SLaurent Pinchart 
lut_destroy(struct vsp1_entity * entity)1815d7936b8SKieran Bingham static void lut_destroy(struct vsp1_entity *entity)
1825d7936b8SKieran Bingham {
1835d7936b8SKieran Bingham 	struct vsp1_lut *lut = to_lut(&entity->subdev);
1845d7936b8SKieran Bingham 
1855d7936b8SKieran Bingham 	vsp1_dl_body_pool_destroy(lut->pool);
1865d7936b8SKieran Bingham }
1875d7936b8SKieran Bingham 
1887b905f05SLaurent Pinchart static const struct vsp1_entity_operations lut_entity_ops = {
18946ce3639SKieran Bingham 	.configure_stream = lut_configure_stream,
19046ce3639SKieran Bingham 	.configure_frame = lut_configure_frame,
1915d7936b8SKieran Bingham 	.destroy = lut_destroy,
1927b905f05SLaurent Pinchart };
1937b905f05SLaurent Pinchart 
1947b905f05SLaurent Pinchart /* -----------------------------------------------------------------------------
195989af883SLaurent Pinchart  * Initialization and Cleanup
196989af883SLaurent Pinchart  */
197989af883SLaurent Pinchart 
vsp1_lut_create(struct vsp1_device * vsp1)198989af883SLaurent Pinchart struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
199989af883SLaurent Pinchart {
200989af883SLaurent Pinchart 	struct vsp1_lut *lut;
201989af883SLaurent Pinchart 	int ret;
202989af883SLaurent Pinchart 
203989af883SLaurent Pinchart 	lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL);
204989af883SLaurent Pinchart 	if (lut == NULL)
205989af883SLaurent Pinchart 		return ERR_PTR(-ENOMEM);
206989af883SLaurent Pinchart 
207f4e37fb7SLaurent Pinchart 	spin_lock_init(&lut->lock);
208f4e37fb7SLaurent Pinchart 
2097b905f05SLaurent Pinchart 	lut->entity.ops = &lut_entity_ops;
210989af883SLaurent Pinchart 	lut->entity.type = VSP1_ENTITY_LUT;
211989af883SLaurent Pinchart 
2126a8e07b2SLaurent Pinchart 	ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops,
2136a8e07b2SLaurent Pinchart 			       MEDIA_ENT_F_PROC_VIDEO_LUT);
214989af883SLaurent Pinchart 	if (ret < 0)
215989af883SLaurent Pinchart 		return ERR_PTR(ret);
216989af883SLaurent Pinchart 
2175d7936b8SKieran Bingham 	/*
2185d7936b8SKieran Bingham 	 * Pre-allocate a body pool, with 3 bodies allowing a userspace update
2195d7936b8SKieran Bingham 	 * before the hardware has committed a previous set of tables, handling
2205d7936b8SKieran Bingham 	 * both the queued and pending dl entries.
2215d7936b8SKieran Bingham 	 */
2225d7936b8SKieran Bingham 	lut->pool = vsp1_dl_body_pool_create(vsp1, 3, LUT_SIZE, 0);
2235d7936b8SKieran Bingham 	if (!lut->pool)
2245d7936b8SKieran Bingham 		return ERR_PTR(-ENOMEM);
2255d7936b8SKieran Bingham 
22642e89bedSLaurent Pinchart 	/* Initialize the control handler. */
22742e89bedSLaurent Pinchart 	v4l2_ctrl_handler_init(&lut->ctrls, 1);
22842e89bedSLaurent Pinchart 	v4l2_ctrl_new_custom(&lut->ctrls, &lut_table_control, NULL);
22942e89bedSLaurent Pinchart 
23042e89bedSLaurent Pinchart 	lut->entity.subdev.ctrl_handler = &lut->ctrls;
23142e89bedSLaurent Pinchart 
23242e89bedSLaurent Pinchart 	if (lut->ctrls.error) {
23342e89bedSLaurent Pinchart 		dev_err(vsp1->dev, "lut: failed to initialize controls\n");
23442e89bedSLaurent Pinchart 		ret = lut->ctrls.error;
23542e89bedSLaurent Pinchart 		vsp1_entity_destroy(&lut->entity);
23642e89bedSLaurent Pinchart 		return ERR_PTR(ret);
23742e89bedSLaurent Pinchart 	}
23842e89bedSLaurent Pinchart 
23942e89bedSLaurent Pinchart 	v4l2_ctrl_handler_setup(&lut->ctrls);
24042e89bedSLaurent Pinchart 
241989af883SLaurent Pinchart 	return lut;
242989af883SLaurent Pinchart }
243