Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[firefly-linux-kernel-4.4.55.git] / drivers / media / platform / vsp1 / vsp1_bru.c
1 /*
2  * vsp1_bru.c  --  R-Car VSP1 Blend ROP 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_bru.h"
21
22 #define BRU_MIN_SIZE                            4U
23 #define BRU_MAX_SIZE                            8190U
24
25 /* -----------------------------------------------------------------------------
26  * Device Access
27  */
28
29 static inline u32 vsp1_bru_read(struct vsp1_bru *bru, u32 reg)
30 {
31         return vsp1_read(bru->entity.vsp1, reg);
32 }
33
34 static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data)
35 {
36         vsp1_write(bru->entity.vsp1, reg, data);
37 }
38
39 /* -----------------------------------------------------------------------------
40  * V4L2 Subdevice Core Operations
41  */
42
43 static bool bru_is_input_enabled(struct vsp1_bru *bru, unsigned int input)
44 {
45         return media_entity_remote_pad(&bru->entity.pads[input]) != NULL;
46 }
47
48 static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
49 {
50         struct vsp1_bru *bru = to_bru(subdev);
51         struct v4l2_mbus_framefmt *format;
52         unsigned int i;
53
54         if (!enable)
55                 return 0;
56
57         format = &bru->entity.formats[BRU_PAD_SOURCE];
58
59         /* The hardware is extremely flexible but we have no userspace API to
60          * expose all the parameters, nor is it clear whether we would have use
61          * cases for all the supported modes. Let's just harcode the parameters
62          * to sane default values for now.
63          */
64
65         /* Disable both color data normalization and dithering. */
66         vsp1_bru_write(bru, VI6_BRU_INCTRL, 0);
67
68         /* Set the background position to cover the whole output image and
69          * set its color to opaque black.
70          */
71         vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
72                        (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
73                        (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
74         vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
75         vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL,
76                        0xff << VI6_BRU_VIRRPF_COL_A_SHIFT);
77
78         /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
79          * unit with a NOP operation to make BRU input 1 available as the
80          * Blend/ROP unit B SRC input.
81          */
82         vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
83                        VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
84                        VI6_BRU_ROP_AROP(VI6_ROP_NOP));
85
86         for (i = 0; i < 4; ++i) {
87                 u32 ctrl = 0;
88
89                 /* Configure all Blend/ROP units corresponding to an enabled BRU
90                  * input for alpha blending. Blend/ROP units corresponding to
91                  * disabled BRU inputs are used in ROP NOP mode to ignore the
92                  * SRC input.
93                  */
94                 if (bru_is_input_enabled(bru, i))
95                         ctrl |= VI6_BRU_CTRL_RBC;
96                 else
97                         ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
98                              |  VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
99
100                 /* Select the virtual RPF as the Blend/ROP unit A DST input to
101                  * serve as a background color.
102                  */
103                 if (i == 0)
104                         ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;
105
106                 /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
107                  * D in that order. The Blend/ROP unit B SRC is hardwired to the
108                  * ROP unit output, the corresponding register bits must be set
109                  * to 0.
110                  */
111                 if (i != 1)
112                         ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
113
114                 vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);
115
116                 /* Harcode the blending formula to
117                  *
118                  *      DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
119                  *      DSTa = DSTa * (1 - SRCa) + SRCa
120                  */
121                 vsp1_bru_write(bru, VI6_BRU_BLD(i),
122                                VI6_BRU_BLD_CCMDX_255_SRC_A |
123                                VI6_BRU_BLD_CCMDY_SRC_A |
124                                VI6_BRU_BLD_ACMDX_255_SRC_A |
125                                VI6_BRU_BLD_ACMDY_COEFY |
126                                (0xff << VI6_BRU_BLD_COEFY_SHIFT));
127         }
128
129         return 0;
130 }
131
132 /* -----------------------------------------------------------------------------
133  * V4L2 Subdevice Pad Operations
134  */
135
136 /*
137  * The BRU can't perform format conversion, all sink and source formats must be
138  * identical. We pick the format on the first sink pad (pad 0) and propagate it
139  * to all other pads.
140  */
141
142 static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
143                               struct v4l2_subdev_fh *fh,
144                               struct v4l2_subdev_mbus_code_enum *code)
145 {
146         static const unsigned int codes[] = {
147                 V4L2_MBUS_FMT_ARGB8888_1X32,
148                 V4L2_MBUS_FMT_AYUV8_1X32,
149         };
150         struct v4l2_mbus_framefmt *format;
151
152         if (code->pad == BRU_PAD_SINK(0)) {
153                 if (code->index >= ARRAY_SIZE(codes))
154                         return -EINVAL;
155
156                 code->code = codes[code->index];
157         } else {
158                 if (code->index)
159                         return -EINVAL;
160
161                 format = v4l2_subdev_get_try_format(fh, BRU_PAD_SINK(0));
162                 code->code = format->code;
163         }
164
165         return 0;
166 }
167
168 static int bru_enum_frame_size(struct v4l2_subdev *subdev,
169                                struct v4l2_subdev_fh *fh,
170                                struct v4l2_subdev_frame_size_enum *fse)
171 {
172         if (fse->index)
173                 return -EINVAL;
174
175         if (fse->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
176             fse->code != V4L2_MBUS_FMT_AYUV8_1X32)
177                 return -EINVAL;
178
179         fse->min_width = BRU_MIN_SIZE;
180         fse->max_width = BRU_MAX_SIZE;
181         fse->min_height = BRU_MIN_SIZE;
182         fse->max_height = BRU_MAX_SIZE;
183
184         return 0;
185 }
186
187 static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
188                                          struct v4l2_subdev_fh *fh,
189                                          unsigned int pad, u32 which)
190 {
191         switch (which) {
192         case V4L2_SUBDEV_FORMAT_TRY:
193                 return v4l2_subdev_get_try_crop(fh, pad);
194         case V4L2_SUBDEV_FORMAT_ACTIVE:
195                 return &bru->compose[pad];
196         default:
197                 return NULL;
198         }
199 }
200
201 static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
202                           struct v4l2_subdev_format *fmt)
203 {
204         struct vsp1_bru *bru = to_bru(subdev);
205
206         fmt->format = *vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad,
207                                                   fmt->which);
208
209         return 0;
210 }
211
212 static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh,
213                            unsigned int pad, struct v4l2_mbus_framefmt *fmt,
214                            enum v4l2_subdev_format_whence which)
215 {
216         struct v4l2_mbus_framefmt *format;
217
218         switch (pad) {
219         case BRU_PAD_SINK(0):
220                 /* Default to YUV if the requested format is not supported. */
221                 if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
222                     fmt->code != V4L2_MBUS_FMT_AYUV8_1X32)
223                         fmt->code = V4L2_MBUS_FMT_AYUV8_1X32;
224                 break;
225
226         default:
227                 /* The BRU can't perform format conversion. */
228                 format = vsp1_entity_get_pad_format(&bru->entity, fh,
229                                                     BRU_PAD_SINK(0), which);
230                 fmt->code = format->code;
231                 break;
232         }
233
234         fmt->width = clamp(fmt->width, BRU_MIN_SIZE, BRU_MAX_SIZE);
235         fmt->height = clamp(fmt->height, BRU_MIN_SIZE, BRU_MAX_SIZE);
236         fmt->field = V4L2_FIELD_NONE;
237         fmt->colorspace = V4L2_COLORSPACE_SRGB;
238 }
239
240 static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
241                           struct v4l2_subdev_format *fmt)
242 {
243         struct vsp1_bru *bru = to_bru(subdev);
244         struct v4l2_mbus_framefmt *format;
245
246         bru_try_format(bru, fh, fmt->pad, &fmt->format, fmt->which);
247
248         format = vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad,
249                                             fmt->which);
250         *format = fmt->format;
251
252         /* Reset the compose rectangle */
253         if (fmt->pad != BRU_PAD_SOURCE) {
254                 struct v4l2_rect *compose;
255
256                 compose = bru_get_compose(bru, fh, fmt->pad, fmt->which);
257                 compose->left = 0;
258                 compose->top = 0;
259                 compose->width = format->width;
260                 compose->height = format->height;
261         }
262
263         /* Propagate the format code to all pads */
264         if (fmt->pad == BRU_PAD_SINK(0)) {
265                 unsigned int i;
266
267                 for (i = 0; i <= BRU_PAD_SOURCE; ++i) {
268                         format = vsp1_entity_get_pad_format(&bru->entity, fh,
269                                                             i, fmt->which);
270                         format->code = fmt->format.code;
271                 }
272         }
273
274         return 0;
275 }
276
277 static int bru_get_selection(struct v4l2_subdev *subdev,
278                              struct v4l2_subdev_fh *fh,
279                              struct v4l2_subdev_selection *sel)
280 {
281         struct vsp1_bru *bru = to_bru(subdev);
282
283         if (sel->pad == BRU_PAD_SOURCE)
284                 return -EINVAL;
285
286         switch (sel->target) {
287         case V4L2_SEL_TGT_COMPOSE_BOUNDS:
288                 sel->r.left = 0;
289                 sel->r.top = 0;
290                 sel->r.width = BRU_MAX_SIZE;
291                 sel->r.height = BRU_MAX_SIZE;
292                 return 0;
293
294         case V4L2_SEL_TGT_COMPOSE:
295                 sel->r = *bru_get_compose(bru, fh, sel->pad, sel->which);
296                 return 0;
297
298         default:
299                 return -EINVAL;
300         }
301 }
302
303 static int bru_set_selection(struct v4l2_subdev *subdev,
304                              struct v4l2_subdev_fh *fh,
305                              struct v4l2_subdev_selection *sel)
306 {
307         struct vsp1_bru *bru = to_bru(subdev);
308         struct v4l2_mbus_framefmt *format;
309         struct v4l2_rect *compose;
310
311         if (sel->pad == BRU_PAD_SOURCE)
312                 return -EINVAL;
313
314         if (sel->target != V4L2_SEL_TGT_COMPOSE)
315                 return -EINVAL;
316
317         /* The compose rectangle top left corner must be inside the output
318          * frame.
319          */
320         format = vsp1_entity_get_pad_format(&bru->entity, fh, BRU_PAD_SOURCE,
321                                             sel->which);
322         sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
323         sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
324
325         /* Scaling isn't supported, the compose rectangle size must be identical
326          * to the sink format size.
327          */
328         format = vsp1_entity_get_pad_format(&bru->entity, fh, sel->pad,
329                                             sel->which);
330         sel->r.width = format->width;
331         sel->r.height = format->height;
332
333         compose = bru_get_compose(bru, fh, sel->pad, sel->which);
334         *compose = sel->r;
335
336         return 0;
337 }
338
339 /* -----------------------------------------------------------------------------
340  * V4L2 Subdevice Operations
341  */
342
343 static struct v4l2_subdev_video_ops bru_video_ops = {
344         .s_stream = bru_s_stream,
345 };
346
347 static struct v4l2_subdev_pad_ops bru_pad_ops = {
348         .enum_mbus_code = bru_enum_mbus_code,
349         .enum_frame_size = bru_enum_frame_size,
350         .get_fmt = bru_get_format,
351         .set_fmt = bru_set_format,
352         .get_selection = bru_get_selection,
353         .set_selection = bru_set_selection,
354 };
355
356 static struct v4l2_subdev_ops bru_ops = {
357         .video  = &bru_video_ops,
358         .pad    = &bru_pad_ops,
359 };
360
361 /* -----------------------------------------------------------------------------
362  * Initialization and Cleanup
363  */
364
365 struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
366 {
367         struct v4l2_subdev *subdev;
368         struct vsp1_bru *bru;
369         int ret;
370
371         bru = devm_kzalloc(vsp1->dev, sizeof(*bru), GFP_KERNEL);
372         if (bru == NULL)
373                 return ERR_PTR(-ENOMEM);
374
375         bru->entity.type = VSP1_ENTITY_BRU;
376
377         ret = vsp1_entity_init(vsp1, &bru->entity, 5);
378         if (ret < 0)
379                 return ERR_PTR(ret);
380
381         /* Initialize the V4L2 subdev. */
382         subdev = &bru->entity.subdev;
383         v4l2_subdev_init(subdev, &bru_ops);
384
385         subdev->entity.ops = &vsp1_media_ops;
386         subdev->internal_ops = &vsp1_subdev_internal_ops;
387         snprintf(subdev->name, sizeof(subdev->name), "%s bru",
388                  dev_name(vsp1->dev));
389         v4l2_set_subdevdata(subdev, bru);
390         subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
391
392         vsp1_entity_init_formats(subdev, NULL);
393
394         return bru;
395 }