xref: /OK3568_Linux_fs/kernel/drivers/media/platform/vsp1/vsp1_lut.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * vsp1_lut.c  --  R-Car VSP1 Look-Up Table
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2013 Renesas Corporation
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/device.h>
11*4882a593Smuzhiyun #include <linux/gfp.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <media/v4l2-subdev.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "vsp1.h"
16*4882a593Smuzhiyun #include "vsp1_dl.h"
17*4882a593Smuzhiyun #include "vsp1_lut.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define LUT_MIN_SIZE				4U
20*4882a593Smuzhiyun #define LUT_MAX_SIZE				8190U
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define LUT_SIZE				256
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
25*4882a593Smuzhiyun  * Device Access
26*4882a593Smuzhiyun  */
27*4882a593Smuzhiyun 
vsp1_lut_write(struct vsp1_lut * lut,struct vsp1_dl_body * dlb,u32 reg,u32 data)28*4882a593Smuzhiyun static inline void vsp1_lut_write(struct vsp1_lut *lut,
29*4882a593Smuzhiyun 				  struct vsp1_dl_body *dlb, u32 reg, u32 data)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	vsp1_dl_body_write(dlb, reg, data);
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
35*4882a593Smuzhiyun  * Controls
36*4882a593Smuzhiyun  */
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define V4L2_CID_VSP1_LUT_TABLE			(V4L2_CID_USER_BASE | 0x1001)
39*4882a593Smuzhiyun 
lut_set_table(struct vsp1_lut * lut,struct v4l2_ctrl * ctrl)40*4882a593Smuzhiyun static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	struct vsp1_dl_body *dlb;
43*4882a593Smuzhiyun 	unsigned int i;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	dlb = vsp1_dl_body_get(lut->pool);
46*4882a593Smuzhiyun 	if (!dlb)
47*4882a593Smuzhiyun 		return -ENOMEM;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	for (i = 0; i < LUT_SIZE; ++i)
50*4882a593Smuzhiyun 		vsp1_dl_body_write(dlb, VI6_LUT_TABLE + 4 * i,
51*4882a593Smuzhiyun 				       ctrl->p_new.p_u32[i]);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	spin_lock_irq(&lut->lock);
54*4882a593Smuzhiyun 	swap(lut->lut, dlb);
55*4882a593Smuzhiyun 	spin_unlock_irq(&lut->lock);
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	vsp1_dl_body_put(dlb);
58*4882a593Smuzhiyun 	return 0;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
lut_s_ctrl(struct v4l2_ctrl * ctrl)61*4882a593Smuzhiyun static int lut_s_ctrl(struct v4l2_ctrl *ctrl)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	struct vsp1_lut *lut =
64*4882a593Smuzhiyun 		container_of(ctrl->handler, struct vsp1_lut, ctrls);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	switch (ctrl->id) {
67*4882a593Smuzhiyun 	case V4L2_CID_VSP1_LUT_TABLE:
68*4882a593Smuzhiyun 		lut_set_table(lut, ctrl);
69*4882a593Smuzhiyun 		break;
70*4882a593Smuzhiyun 	}
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	return 0;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun static const struct v4l2_ctrl_ops lut_ctrl_ops = {
76*4882a593Smuzhiyun 	.s_ctrl = lut_s_ctrl,
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun static const struct v4l2_ctrl_config lut_table_control = {
80*4882a593Smuzhiyun 	.ops = &lut_ctrl_ops,
81*4882a593Smuzhiyun 	.id = V4L2_CID_VSP1_LUT_TABLE,
82*4882a593Smuzhiyun 	.name = "Look-Up Table",
83*4882a593Smuzhiyun 	.type = V4L2_CTRL_TYPE_U32,
84*4882a593Smuzhiyun 	.min = 0x00000000,
85*4882a593Smuzhiyun 	.max = 0x00ffffff,
86*4882a593Smuzhiyun 	.step = 1,
87*4882a593Smuzhiyun 	.def = 0,
88*4882a593Smuzhiyun 	.dims = { LUT_SIZE },
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
92*4882a593Smuzhiyun  * V4L2 Subdevice Pad Operations
93*4882a593Smuzhiyun  */
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun static const unsigned int lut_codes[] = {
96*4882a593Smuzhiyun 	MEDIA_BUS_FMT_ARGB8888_1X32,
97*4882a593Smuzhiyun 	MEDIA_BUS_FMT_AHSV8888_1X32,
98*4882a593Smuzhiyun 	MEDIA_BUS_FMT_AYUV8_1X32,
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun 
lut_enum_mbus_code(struct v4l2_subdev * subdev,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code)101*4882a593Smuzhiyun static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
102*4882a593Smuzhiyun 			      struct v4l2_subdev_pad_config *cfg,
103*4882a593Smuzhiyun 			      struct v4l2_subdev_mbus_code_enum *code)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	return vsp1_subdev_enum_mbus_code(subdev, cfg, code, lut_codes,
106*4882a593Smuzhiyun 					  ARRAY_SIZE(lut_codes));
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
lut_enum_frame_size(struct v4l2_subdev * subdev,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_frame_size_enum * fse)109*4882a593Smuzhiyun static int lut_enum_frame_size(struct v4l2_subdev *subdev,
110*4882a593Smuzhiyun 			       struct v4l2_subdev_pad_config *cfg,
111*4882a593Smuzhiyun 			       struct v4l2_subdev_frame_size_enum *fse)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LUT_MIN_SIZE,
114*4882a593Smuzhiyun 					   LUT_MIN_SIZE, LUT_MAX_SIZE,
115*4882a593Smuzhiyun 					   LUT_MAX_SIZE);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
lut_set_format(struct v4l2_subdev * subdev,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)118*4882a593Smuzhiyun static int lut_set_format(struct v4l2_subdev *subdev,
119*4882a593Smuzhiyun 			  struct v4l2_subdev_pad_config *cfg,
120*4882a593Smuzhiyun 			  struct v4l2_subdev_format *fmt)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	return vsp1_subdev_set_pad_format(subdev, cfg, fmt, lut_codes,
123*4882a593Smuzhiyun 					  ARRAY_SIZE(lut_codes),
124*4882a593Smuzhiyun 					  LUT_MIN_SIZE, LUT_MIN_SIZE,
125*4882a593Smuzhiyun 					  LUT_MAX_SIZE, LUT_MAX_SIZE);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
129*4882a593Smuzhiyun  * V4L2 Subdevice Operations
130*4882a593Smuzhiyun  */
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun static const struct v4l2_subdev_pad_ops lut_pad_ops = {
133*4882a593Smuzhiyun 	.init_cfg = vsp1_entity_init_cfg,
134*4882a593Smuzhiyun 	.enum_mbus_code = lut_enum_mbus_code,
135*4882a593Smuzhiyun 	.enum_frame_size = lut_enum_frame_size,
136*4882a593Smuzhiyun 	.get_fmt = vsp1_subdev_get_pad_format,
137*4882a593Smuzhiyun 	.set_fmt = lut_set_format,
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun static const struct v4l2_subdev_ops lut_ops = {
141*4882a593Smuzhiyun 	.pad    = &lut_pad_ops,
142*4882a593Smuzhiyun };
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
145*4882a593Smuzhiyun  * VSP1 Entity Operations
146*4882a593Smuzhiyun  */
147*4882a593Smuzhiyun 
lut_configure_stream(struct vsp1_entity * entity,struct vsp1_pipeline * pipe,struct vsp1_dl_list * dl,struct vsp1_dl_body * dlb)148*4882a593Smuzhiyun static void lut_configure_stream(struct vsp1_entity *entity,
149*4882a593Smuzhiyun 				 struct vsp1_pipeline *pipe,
150*4882a593Smuzhiyun 				 struct vsp1_dl_list *dl,
151*4882a593Smuzhiyun 				 struct vsp1_dl_body *dlb)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	struct vsp1_lut *lut = to_lut(&entity->subdev);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	vsp1_lut_write(lut, dlb, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
lut_configure_frame(struct vsp1_entity * entity,struct vsp1_pipeline * pipe,struct vsp1_dl_list * dl,struct vsp1_dl_body * dlb)158*4882a593Smuzhiyun static void lut_configure_frame(struct vsp1_entity *entity,
159*4882a593Smuzhiyun 				struct vsp1_pipeline *pipe,
160*4882a593Smuzhiyun 				struct vsp1_dl_list *dl,
161*4882a593Smuzhiyun 				struct vsp1_dl_body *dlb)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	struct vsp1_lut *lut = to_lut(&entity->subdev);
164*4882a593Smuzhiyun 	struct vsp1_dl_body *lut_dlb;
165*4882a593Smuzhiyun 	unsigned long flags;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	spin_lock_irqsave(&lut->lock, flags);
168*4882a593Smuzhiyun 	lut_dlb = lut->lut;
169*4882a593Smuzhiyun 	lut->lut = NULL;
170*4882a593Smuzhiyun 	spin_unlock_irqrestore(&lut->lock, flags);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	if (lut_dlb) {
173*4882a593Smuzhiyun 		vsp1_dl_list_add_body(dl, lut_dlb);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 		/* Release our local reference. */
176*4882a593Smuzhiyun 		vsp1_dl_body_put(lut_dlb);
177*4882a593Smuzhiyun 	}
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
lut_destroy(struct vsp1_entity * entity)180*4882a593Smuzhiyun static void lut_destroy(struct vsp1_entity *entity)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct vsp1_lut *lut = to_lut(&entity->subdev);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	vsp1_dl_body_pool_destroy(lut->pool);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun static const struct vsp1_entity_operations lut_entity_ops = {
188*4882a593Smuzhiyun 	.configure_stream = lut_configure_stream,
189*4882a593Smuzhiyun 	.configure_frame = lut_configure_frame,
190*4882a593Smuzhiyun 	.destroy = lut_destroy,
191*4882a593Smuzhiyun };
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
194*4882a593Smuzhiyun  * Initialization and Cleanup
195*4882a593Smuzhiyun  */
196*4882a593Smuzhiyun 
vsp1_lut_create(struct vsp1_device * vsp1)197*4882a593Smuzhiyun struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	struct vsp1_lut *lut;
200*4882a593Smuzhiyun 	int ret;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL);
203*4882a593Smuzhiyun 	if (lut == NULL)
204*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	spin_lock_init(&lut->lock);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	lut->entity.ops = &lut_entity_ops;
209*4882a593Smuzhiyun 	lut->entity.type = VSP1_ENTITY_LUT;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops,
212*4882a593Smuzhiyun 			       MEDIA_ENT_F_PROC_VIDEO_LUT);
213*4882a593Smuzhiyun 	if (ret < 0)
214*4882a593Smuzhiyun 		return ERR_PTR(ret);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	/*
217*4882a593Smuzhiyun 	 * Pre-allocate a body pool, with 3 bodies allowing a userspace update
218*4882a593Smuzhiyun 	 * before the hardware has committed a previous set of tables, handling
219*4882a593Smuzhiyun 	 * both the queued and pending dl entries.
220*4882a593Smuzhiyun 	 */
221*4882a593Smuzhiyun 	lut->pool = vsp1_dl_body_pool_create(vsp1, 3, LUT_SIZE, 0);
222*4882a593Smuzhiyun 	if (!lut->pool)
223*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	/* Initialize the control handler. */
226*4882a593Smuzhiyun 	v4l2_ctrl_handler_init(&lut->ctrls, 1);
227*4882a593Smuzhiyun 	v4l2_ctrl_new_custom(&lut->ctrls, &lut_table_control, NULL);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	lut->entity.subdev.ctrl_handler = &lut->ctrls;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	if (lut->ctrls.error) {
232*4882a593Smuzhiyun 		dev_err(vsp1->dev, "lut: failed to initialize controls\n");
233*4882a593Smuzhiyun 		ret = lut->ctrls.error;
234*4882a593Smuzhiyun 		vsp1_entity_destroy(&lut->entity);
235*4882a593Smuzhiyun 		return ERR_PTR(ret);
236*4882a593Smuzhiyun 	}
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	v4l2_ctrl_handler_setup(&lut->ctrls);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	return lut;
241*4882a593Smuzhiyun }
242