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