blob: 96a448e1504c7798cf53471b7177f6c33a8d2cdc [file] [log] [blame]
Laurent Pinchart1c4b5f42018-04-22 17:33:20 -04001// SPDX-License-Identifier: GPL-2.0+
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -02002/*
3 * vsp1_clu.c -- R-Car VSP1 Cubic Look-Up Table
4 *
5 * Copyright (C) 2015-2016 Renesas Electronics Corporation
6 *
7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -02008 */
9
10#include <linux/device.h>
11#include <linux/slab.h>
12
13#include <media/v4l2-subdev.h>
14
15#include "vsp1.h"
16#include "vsp1_clu.h"
17#include "vsp1_dl.h"
18
19#define CLU_MIN_SIZE 4U
20#define CLU_MAX_SIZE 8190U
21
22/* -----------------------------------------------------------------------------
23 * Device Access
24 */
25
26static inline void vsp1_clu_write(struct vsp1_clu *clu, struct vsp1_dl_list *dl,
27 u32 reg, u32 data)
28{
29 vsp1_dl_list_write(dl, reg, data);
30}
31
32/* -----------------------------------------------------------------------------
33 * Controls
34 */
35
36#define V4L2_CID_VSP1_CLU_TABLE (V4L2_CID_USER_BASE | 0x1001)
37#define V4L2_CID_VSP1_CLU_MODE (V4L2_CID_USER_BASE | 0x1002)
38#define V4L2_CID_VSP1_CLU_MODE_2D 0
39#define V4L2_CID_VSP1_CLU_MODE_3D 1
40
41static int clu_set_table(struct vsp1_clu *clu, struct v4l2_ctrl *ctrl)
42{
43 struct vsp1_dl_body *dlb;
44 unsigned int i;
45
46 dlb = vsp1_dl_fragment_alloc(clu->entity.vsp1, 1 + 17 * 17 * 17);
47 if (!dlb)
48 return -ENOMEM;
49
50 vsp1_dl_fragment_write(dlb, VI6_CLU_ADDR, 0);
51 for (i = 0; i < 17 * 17 * 17; ++i)
52 vsp1_dl_fragment_write(dlb, VI6_CLU_DATA, ctrl->p_new.p_u32[i]);
53
Laurent Pinchart20fab5e2016-06-11 04:11:27 -030054 spin_lock_irq(&clu->lock);
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -020055 swap(clu->clu, dlb);
Laurent Pinchart20fab5e2016-06-11 04:11:27 -030056 spin_unlock_irq(&clu->lock);
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -020057
58 vsp1_dl_fragment_free(dlb);
59 return 0;
60}
61
62static int clu_s_ctrl(struct v4l2_ctrl *ctrl)
63{
64 struct vsp1_clu *clu =
65 container_of(ctrl->handler, struct vsp1_clu, ctrls);
66
67 switch (ctrl->id) {
68 case V4L2_CID_VSP1_CLU_TABLE:
69 clu_set_table(clu, ctrl);
70 break;
71
72 case V4L2_CID_VSP1_CLU_MODE:
73 clu->mode = ctrl->val;
74 break;
75 }
76
77 return 0;
78}
79
80static const struct v4l2_ctrl_ops clu_ctrl_ops = {
81 .s_ctrl = clu_s_ctrl,
82};
83
84static const struct v4l2_ctrl_config clu_table_control = {
85 .ops = &clu_ctrl_ops,
86 .id = V4L2_CID_VSP1_CLU_TABLE,
87 .name = "Look-Up Table",
88 .type = V4L2_CTRL_TYPE_U32,
89 .min = 0x00000000,
90 .max = 0x00ffffff,
91 .step = 1,
92 .def = 0,
93 .dims = { 17, 17, 17 },
94};
95
96static const char * const clu_mode_menu[] = {
97 "2D",
98 "3D",
99 NULL,
100};
101
102static const struct v4l2_ctrl_config clu_mode_control = {
103 .ops = &clu_ctrl_ops,
104 .id = V4L2_CID_VSP1_CLU_MODE,
105 .name = "Mode",
106 .type = V4L2_CTRL_TYPE_MENU,
107 .min = 0,
108 .max = 1,
109 .def = 1,
110 .qmenu = clu_mode_menu,
111};
112
113/* -----------------------------------------------------------------------------
114 * V4L2 Subdevice Pad Operations
115 */
116
Laurent Pinchartb4ccae12017-11-27 14:59:45 -0500117static const unsigned int clu_codes[] = {
118 MEDIA_BUS_FMT_ARGB8888_1X32,
119 MEDIA_BUS_FMT_AHSV8888_1X32,
120 MEDIA_BUS_FMT_AYUV8_1X32,
121};
122
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -0200123static int clu_enum_mbus_code(struct v4l2_subdev *subdev,
124 struct v4l2_subdev_pad_config *cfg,
125 struct v4l2_subdev_mbus_code_enum *code)
126{
Laurent Pinchartb4ccae12017-11-27 14:59:45 -0500127 return vsp1_subdev_enum_mbus_code(subdev, cfg, code, clu_codes,
128 ARRAY_SIZE(clu_codes));
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -0200129}
130
131static int clu_enum_frame_size(struct v4l2_subdev *subdev,
132 struct v4l2_subdev_pad_config *cfg,
133 struct v4l2_subdev_frame_size_enum *fse)
134{
135 return vsp1_subdev_enum_frame_size(subdev, cfg, fse, CLU_MIN_SIZE,
136 CLU_MIN_SIZE, CLU_MAX_SIZE,
137 CLU_MAX_SIZE);
138}
139
140static int clu_set_format(struct v4l2_subdev *subdev,
141 struct v4l2_subdev_pad_config *cfg,
142 struct v4l2_subdev_format *fmt)
143{
Laurent Pinchartb4ccae12017-11-27 14:59:45 -0500144 return vsp1_subdev_set_pad_format(subdev, cfg, fmt, clu_codes,
145 ARRAY_SIZE(clu_codes),
146 CLU_MIN_SIZE, CLU_MIN_SIZE,
147 CLU_MAX_SIZE, CLU_MAX_SIZE);
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -0200148}
149
150/* -----------------------------------------------------------------------------
151 * V4L2 Subdevice Operations
152 */
153
154static const struct v4l2_subdev_pad_ops clu_pad_ops = {
155 .init_cfg = vsp1_entity_init_cfg,
156 .enum_mbus_code = clu_enum_mbus_code,
157 .enum_frame_size = clu_enum_frame_size,
158 .get_fmt = vsp1_subdev_get_pad_format,
159 .set_fmt = clu_set_format,
160};
161
162static const struct v4l2_subdev_ops clu_ops = {
163 .pad = &clu_pad_ops,
164};
165
166/* -----------------------------------------------------------------------------
167 * VSP1 Entity Operations
168 */
169
170static void clu_configure(struct vsp1_entity *entity,
171 struct vsp1_pipeline *pipe,
Laurent Pinchartd21fbbb2016-09-11 19:39:30 -0300172 struct vsp1_dl_list *dl,
173 enum vsp1_entity_params params)
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -0200174{
175 struct vsp1_clu *clu = to_clu(&entity->subdev);
Laurent Pinchart20fab5e2016-06-11 04:11:27 -0300176 struct vsp1_dl_body *dlb;
177 unsigned long flags;
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -0200178 u32 ctrl = VI6_CLU_CTRL_AAI | VI6_CLU_CTRL_MVS | VI6_CLU_CTRL_EN;
179
Laurent Pinchartd21fbbb2016-09-11 19:39:30 -0300180 switch (params) {
181 case VSP1_ENTITY_PARAMS_INIT: {
Mauro Carvalho Chehabb6187392016-09-19 15:18:01 -0300182 /*
183 * The format can't be changed during streaming, only verify it
Laurent Pinchartd21fbbb2016-09-11 19:39:30 -0300184 * at setup time and store the information internally for future
185 * runtime configuration calls.
186 */
Laurent Pinchart20fab5e2016-06-11 04:11:27 -0300187 struct v4l2_mbus_framefmt *format;
188
189 format = vsp1_entity_get_pad_format(&clu->entity,
190 clu->entity.config,
191 CLU_PAD_SINK);
192 clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32;
Laurent Pinchartd21fbbb2016-09-11 19:39:30 -0300193 break;
Laurent Pinchart20fab5e2016-06-11 04:11:27 -0300194 }
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -0200195
Laurent Pinchart8ddf3782016-09-12 09:50:13 -0300196 case VSP1_ENTITY_PARAMS_PARTITION:
197 break;
198
Laurent Pinchartd21fbbb2016-09-11 19:39:30 -0300199 case VSP1_ENTITY_PARAMS_RUNTIME:
200 /* 2D mode can only be used with the YCbCr pixel encoding. */
201 if (clu->mode == V4L2_CID_VSP1_CLU_MODE_2D && clu->yuv_mode)
202 ctrl |= VI6_CLU_CTRL_AX1I_2D | VI6_CLU_CTRL_AX2I_2D
203 | VI6_CLU_CTRL_OS0_2D | VI6_CLU_CTRL_OS1_2D
204 | VI6_CLU_CTRL_OS2_2D | VI6_CLU_CTRL_M2D;
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -0200205
Laurent Pinchartd21fbbb2016-09-11 19:39:30 -0300206 vsp1_clu_write(clu, dl, VI6_CLU_CTRL, ctrl);
Laurent Pinchart20fab5e2016-06-11 04:11:27 -0300207
Laurent Pinchartd21fbbb2016-09-11 19:39:30 -0300208 spin_lock_irqsave(&clu->lock, flags);
209 dlb = clu->clu;
210 clu->clu = NULL;
211 spin_unlock_irqrestore(&clu->lock, flags);
Laurent Pinchart20fab5e2016-06-11 04:11:27 -0300212
Laurent Pinchartd21fbbb2016-09-11 19:39:30 -0300213 if (dlb)
214 vsp1_dl_list_add_fragment(dl, dlb);
215 break;
216 }
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -0200217}
218
219static const struct vsp1_entity_operations clu_entity_ops = {
220 .configure = clu_configure,
221};
222
223/* -----------------------------------------------------------------------------
224 * Initialization and Cleanup
225 */
226
227struct vsp1_clu *vsp1_clu_create(struct vsp1_device *vsp1)
228{
229 struct vsp1_clu *clu;
230 int ret;
231
232 clu = devm_kzalloc(vsp1->dev, sizeof(*clu), GFP_KERNEL);
233 if (clu == NULL)
234 return ERR_PTR(-ENOMEM);
235
Laurent Pinchart20fab5e2016-06-11 04:11:27 -0300236 spin_lock_init(&clu->lock);
237
Laurent Pinchart1fd87bf2015-11-11 23:04:44 -0200238 clu->entity.ops = &clu_entity_ops;
239 clu->entity.type = VSP1_ENTITY_CLU;
240
241 ret = vsp1_entity_init(vsp1, &clu->entity, "clu", 2, &clu_ops,
242 MEDIA_ENT_F_PROC_VIDEO_LUT);
243 if (ret < 0)
244 return ERR_PTR(ret);
245
246 /* Initialize the control handler. */
247 v4l2_ctrl_handler_init(&clu->ctrls, 2);
248 v4l2_ctrl_new_custom(&clu->ctrls, &clu_table_control, NULL);
249 v4l2_ctrl_new_custom(&clu->ctrls, &clu_mode_control, NULL);
250
251 clu->entity.subdev.ctrl_handler = &clu->ctrls;
252
253 if (clu->ctrls.error) {
254 dev_err(vsp1->dev, "clu: failed to initialize controls\n");
255 ret = clu->ctrls.error;
256 vsp1_entity_destroy(&clu->entity);
257 return ERR_PTR(ret);
258 }
259
260 v4l2_ctrl_handler_setup(&clu->ctrls);
261
262 return clu;
263}