Merge tag 'v3.14.25' into backport/v3.14.24-ltsi-rc1+v3.14.25/snapshot-merge.wip
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / media / platform / vsp1 / vsp1_sru.c
1 /*
2  * vsp1_sru.c  --  R-Car VSP1 Super Resolution Unit
3  *
4  * Copyright (C) 2013 Renesas Corporation
5  *
6  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13
14 #include <linux/device.h>
15 #include <linux/gfp.h>
16
17 #include <media/v4l2-subdev.h>
18
19 #include "vsp1.h"
20 #include "vsp1_sru.h"
21
22 #define SRU_MIN_SIZE                            4U
23 #define SRU_MAX_SIZE                            8190U
24
25 /* -----------------------------------------------------------------------------
26  * Device Access
27  */
28
29 static inline u32 vsp1_sru_read(struct vsp1_sru *sru, u32 reg)
30 {
31         return vsp1_read(sru->entity.vsp1, reg);
32 }
33
34 static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data)
35 {
36         vsp1_write(sru->entity.vsp1, reg, data);
37 }
38
39 /* -----------------------------------------------------------------------------
40  * Controls
41  */
42
43 #define V4L2_CID_VSP1_SRU_INTENSITY             (V4L2_CID_USER_BASE + 1)
44
45 struct vsp1_sru_param {
46         u32 ctrl0;
47         u32 ctrl2;
48 };
49
50 #define VI6_SRU_CTRL0_PARAMS(p0, p1)                    \
51         (((p0) << VI6_SRU_CTRL0_PARAM0_SHIFT) |         \
52          ((p1) << VI6_SRU_CTRL0_PARAM1_SHIFT))
53
54 #define VI6_SRU_CTRL2_PARAMS(p6, p7, p8)                \
55         (((p6) << VI6_SRU_CTRL2_PARAM6_SHIFT) |         \
56          ((p7) << VI6_SRU_CTRL2_PARAM7_SHIFT) |         \
57          ((p8) << VI6_SRU_CTRL2_PARAM8_SHIFT))
58
59 static const struct vsp1_sru_param vsp1_sru_params[] = {
60         {
61                 .ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN,
62                 .ctrl2 = VI6_SRU_CTRL2_PARAMS(24, 40, 255),
63         }, {
64                 .ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN,
65                 .ctrl2 = VI6_SRU_CTRL2_PARAMS(8, 16, 255),
66         }, {
67                 .ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN,
68                 .ctrl2 = VI6_SRU_CTRL2_PARAMS(36, 60, 255),
69         }, {
70                 .ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN,
71                 .ctrl2 = VI6_SRU_CTRL2_PARAMS(12, 27, 255),
72         }, {
73                 .ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN,
74                 .ctrl2 = VI6_SRU_CTRL2_PARAMS(48, 80, 255),
75         }, {
76                 .ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN,
77                 .ctrl2 = VI6_SRU_CTRL2_PARAMS(16, 36, 255),
78         },
79 };
80
81 static int sru_s_ctrl(struct v4l2_ctrl *ctrl)
82 {
83         struct vsp1_sru *sru =
84                 container_of(ctrl->handler, struct vsp1_sru, ctrls);
85         const struct vsp1_sru_param *param;
86         u32 value;
87
88         switch (ctrl->id) {
89         case V4L2_CID_VSP1_SRU_INTENSITY:
90                 param = &vsp1_sru_params[ctrl->val - 1];
91
92                 value = vsp1_sru_read(sru, VI6_SRU_CTRL0);
93                 value &= ~(VI6_SRU_CTRL0_PARAM0_MASK |
94                            VI6_SRU_CTRL0_PARAM1_MASK);
95                 value |= param->ctrl0;
96                 vsp1_sru_write(sru, VI6_SRU_CTRL0, value);
97
98                 vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
99                 break;
100         }
101
102         return 0;
103 }
104
105 static const struct v4l2_ctrl_ops sru_ctrl_ops = {
106         .s_ctrl = sru_s_ctrl,
107 };
108
109 static const struct v4l2_ctrl_config sru_intensity_control = {
110         .ops = &sru_ctrl_ops,
111         .id = V4L2_CID_VSP1_SRU_INTENSITY,
112         .name = "Intensity",
113         .type = V4L2_CTRL_TYPE_INTEGER,
114         .min = 1,
115         .max = 6,
116         .def = 1,
117         .step = 1,
118 };
119
120 /* -----------------------------------------------------------------------------
121  * V4L2 Subdevice Core Operations
122  */
123
124 static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
125 {
126         struct vsp1_sru *sru = to_sru(subdev);
127         struct v4l2_mbus_framefmt *input;
128         struct v4l2_mbus_framefmt *output;
129         u32 ctrl0;
130         int ret;
131
132         ret = vsp1_entity_set_streaming(&sru->entity, enable);
133         if (ret < 0)
134                 return ret;
135
136         if (!enable)
137                 return 0;
138
139         input = &sru->entity.formats[SRU_PAD_SINK];
140         output = &sru->entity.formats[SRU_PAD_SOURCE];
141
142         if (input->code == V4L2_MBUS_FMT_ARGB8888_1X32)
143                 ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
144                       | VI6_SRU_CTRL0_PARAM4;
145         else
146                 ctrl0 = VI6_SRU_CTRL0_PARAM3;
147
148         if (input->width != output->width)
149                 ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
150
151         /* Take the control handler lock to ensure that the CTRL0 value won't be
152          * changed behind our back by a set control operation.
153          */
154         mutex_lock(sru->ctrls.lock);
155         ctrl0 |= vsp1_sru_read(sru, VI6_SRU_CTRL0)
156                & (VI6_SRU_CTRL0_PARAM0_MASK | VI6_SRU_CTRL0_PARAM1_MASK);
157         mutex_unlock(sru->ctrls.lock);
158
159         vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
160
161         return 0;
162 }
163
164 /* -----------------------------------------------------------------------------
165  * V4L2 Subdevice Pad Operations
166  */
167
168 static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
169                               struct v4l2_subdev_fh *fh,
170                               struct v4l2_subdev_mbus_code_enum *code)
171 {
172         static const unsigned int codes[] = {
173                 V4L2_MBUS_FMT_ARGB8888_1X32,
174                 V4L2_MBUS_FMT_AYUV8_1X32,
175         };
176         struct v4l2_mbus_framefmt *format;
177
178         if (code->pad == SRU_PAD_SINK) {
179                 if (code->index >= ARRAY_SIZE(codes))
180                         return -EINVAL;
181
182                 code->code = codes[code->index];
183         } else {
184                 /* The SRU can't perform format conversion, the sink format is
185                  * always identical to the source format.
186                  */
187                 if (code->index)
188                         return -EINVAL;
189
190                 format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK);
191                 code->code = format->code;
192         }
193
194         return 0;
195 }
196
197 static int sru_enum_frame_size(struct v4l2_subdev *subdev,
198                                struct v4l2_subdev_fh *fh,
199                                struct v4l2_subdev_frame_size_enum *fse)
200 {
201         struct v4l2_mbus_framefmt *format;
202
203         format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK);
204
205         if (fse->index || fse->code != format->code)
206                 return -EINVAL;
207
208         if (fse->pad == SRU_PAD_SINK) {
209                 fse->min_width = SRU_MIN_SIZE;
210                 fse->max_width = SRU_MAX_SIZE;
211                 fse->min_height = SRU_MIN_SIZE;
212                 fse->max_height = SRU_MAX_SIZE;
213         } else {
214                 fse->min_width = format->width;
215                 fse->min_height = format->height;
216                 if (format->width <= SRU_MAX_SIZE / 2 &&
217                     format->height <= SRU_MAX_SIZE / 2) {
218                         fse->max_width = format->width * 2;
219                         fse->max_height = format->height * 2;
220                 } else {
221                         fse->max_width = format->width;
222                         fse->max_height = format->height;
223                 }
224         }
225
226         return 0;
227 }
228
229 static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
230                           struct v4l2_subdev_format *fmt)
231 {
232         struct vsp1_sru *sru = to_sru(subdev);
233
234         fmt->format = *vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad,
235                                                   fmt->which);
236
237         return 0;
238 }
239
240 static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh,
241                            unsigned int pad, struct v4l2_mbus_framefmt *fmt,
242                            enum v4l2_subdev_format_whence which)
243 {
244         struct v4l2_mbus_framefmt *format;
245         unsigned int input_area;
246         unsigned int output_area;
247
248         switch (pad) {
249         case SRU_PAD_SINK:
250                 /* Default to YUV if the requested format is not supported. */
251                 if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
252                     fmt->code != V4L2_MBUS_FMT_AYUV8_1X32)
253                         fmt->code = V4L2_MBUS_FMT_AYUV8_1X32;
254
255                 fmt->width = clamp(fmt->width, SRU_MIN_SIZE, SRU_MAX_SIZE);
256                 fmt->height = clamp(fmt->height, SRU_MIN_SIZE, SRU_MAX_SIZE);
257                 break;
258
259         case SRU_PAD_SOURCE:
260                 /* The SRU can't perform format conversion. */
261                 format = vsp1_entity_get_pad_format(&sru->entity, fh,
262                                                     SRU_PAD_SINK, which);
263                 fmt->code = format->code;
264
265                 /* We can upscale by 2 in both direction, but not independently.
266                  * Compare the input and output rectangles areas (avoiding
267                  * integer overflows on the output): if the requested output
268                  * area is larger than 1.5^2 the input area upscale by two,
269                  * otherwise don't scale.
270                  */
271                 input_area = format->width * format->height;
272                 output_area = min(fmt->width, SRU_MAX_SIZE)
273                             * min(fmt->height, SRU_MAX_SIZE);
274
275                 if (fmt->width <= SRU_MAX_SIZE / 2 &&
276                     fmt->height <= SRU_MAX_SIZE / 2 &&
277                     output_area > input_area * 9 / 4) {
278                         fmt->width = format->width * 2;
279                         fmt->height = format->height * 2;
280                 } else {
281                         fmt->width = format->width;
282                         fmt->height = format->height;
283                 }
284                 break;
285         }
286
287         fmt->field = V4L2_FIELD_NONE;
288         fmt->colorspace = V4L2_COLORSPACE_SRGB;
289 }
290
291 static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
292                           struct v4l2_subdev_format *fmt)
293 {
294         struct vsp1_sru *sru = to_sru(subdev);
295         struct v4l2_mbus_framefmt *format;
296
297         sru_try_format(sru, fh, fmt->pad, &fmt->format, fmt->which);
298
299         format = vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad,
300                                             fmt->which);
301         *format = fmt->format;
302
303         if (fmt->pad == SRU_PAD_SINK) {
304                 /* Propagate the format to the source pad. */
305                 format = vsp1_entity_get_pad_format(&sru->entity, fh,
306                                                     SRU_PAD_SOURCE, fmt->which);
307                 *format = fmt->format;
308
309                 sru_try_format(sru, fh, SRU_PAD_SOURCE, format, fmt->which);
310         }
311
312         return 0;
313 }
314
315 /* -----------------------------------------------------------------------------
316  * V4L2 Subdevice Operations
317  */
318
319 static struct v4l2_subdev_video_ops sru_video_ops = {
320         .s_stream = sru_s_stream,
321 };
322
323 static struct v4l2_subdev_pad_ops sru_pad_ops = {
324         .enum_mbus_code = sru_enum_mbus_code,
325         .enum_frame_size = sru_enum_frame_size,
326         .get_fmt = sru_get_format,
327         .set_fmt = sru_set_format,
328 };
329
330 static struct v4l2_subdev_ops sru_ops = {
331         .video  = &sru_video_ops,
332         .pad    = &sru_pad_ops,
333 };
334
335 /* -----------------------------------------------------------------------------
336  * Initialization and Cleanup
337  */
338
339 struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
340 {
341         struct v4l2_subdev *subdev;
342         struct vsp1_sru *sru;
343         int ret;
344
345         sru = devm_kzalloc(vsp1->dev, sizeof(*sru), GFP_KERNEL);
346         if (sru == NULL)
347                 return ERR_PTR(-ENOMEM);
348
349         sru->entity.type = VSP1_ENTITY_SRU;
350
351         ret = vsp1_entity_init(vsp1, &sru->entity, 2);
352         if (ret < 0)
353                 return ERR_PTR(ret);
354
355         /* Initialize the V4L2 subdev. */
356         subdev = &sru->entity.subdev;
357         v4l2_subdev_init(subdev, &sru_ops);
358
359         subdev->entity.ops = &vsp1_media_ops;
360         subdev->internal_ops = &vsp1_subdev_internal_ops;
361         snprintf(subdev->name, sizeof(subdev->name), "%s sru",
362                  dev_name(vsp1->dev));
363         v4l2_set_subdevdata(subdev, sru);
364         subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
365
366         vsp1_entity_init_formats(subdev, NULL);
367
368         /* Initialize the control handler. */
369         v4l2_ctrl_handler_init(&sru->ctrls, 1);
370         v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
371
372         sru->entity.subdev.ctrl_handler = &sru->ctrls;
373
374         if (sru->ctrls.error) {
375                 dev_err(vsp1->dev, "sru: failed to initialize controls\n");
376                 ret = sru->ctrls.error;
377                 vsp1_entity_destroy(&sru->entity);
378                 return ERR_PTR(ret);
379         }
380
381         return sru;
382 }