blob: 8cb87e96b78bb7edc02518eb080da9d85fe6f104 [file] [log] [blame]
Laurent Pinchart26e0ca22013-06-04 11:22:30 -03001/*
2 * vsp1_rwpf.c -- R-Car VSP1 Read and Write Pixel Formatters
3 *
Laurent Pinchart8a1edc52014-02-06 14:42:31 -03004 * Copyright (C) 2013-2014 Renesas Electronics Corporation
Laurent Pinchart26e0ca22013-06-04 11:22:30 -03005 *
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 <media/v4l2-subdev.h>
15
16#include "vsp1.h"
17#include "vsp1_rwpf.h"
18#include "vsp1_video.h"
19
20#define RWPF_MIN_WIDTH 1
21#define RWPF_MIN_HEIGHT 1
22
Laurent Pinchartc6c8efb2015-11-22 13:37:45 -020023struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
24 struct v4l2_subdev_pad_config *config)
25{
26 return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config,
27 RWPF_PAD_SINK);
28}
29
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030030/* -----------------------------------------------------------------------------
31 * V4L2 Subdevice Pad Operations
32 */
33
Laurent Pinchartc6c8efb2015-11-22 13:37:45 -020034static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
35 struct v4l2_subdev_pad_config *cfg,
36 struct v4l2_subdev_mbus_code_enum *code)
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030037{
38 static const unsigned int codes[] = {
Boris BREZILLON27ffaeb2014-11-10 14:28:31 -030039 MEDIA_BUS_FMT_ARGB8888_1X32,
40 MEDIA_BUS_FMT_AYUV8_1X32,
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030041 };
42
43 if (code->index >= ARRAY_SIZE(codes))
44 return -EINVAL;
45
46 code->code = codes[code->index];
47
48 return 0;
49}
50
Laurent Pinchartc6c8efb2015-11-22 13:37:45 -020051static int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
52 struct v4l2_subdev_pad_config *cfg,
53 struct v4l2_subdev_frame_size_enum *fse)
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030054{
55 struct vsp1_rwpf *rwpf = to_rwpf(subdev);
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030056
Laurent Pinchart076e8342016-02-24 20:25:42 -030057 return vsp1_subdev_enum_frame_size(subdev, cfg, fse, RWPF_MIN_WIDTH,
58 RWPF_MIN_HEIGHT, rwpf->max_width,
59 rwpf->max_height);
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030060}
61
Laurent Pinchartc6c8efb2015-11-22 13:37:45 -020062static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
63 struct v4l2_subdev_pad_config *cfg,
64 struct v4l2_subdev_format *fmt)
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030065{
66 struct vsp1_rwpf *rwpf = to_rwpf(subdev);
Laurent Pincharte790c3c2015-11-15 19:14:22 -020067 struct v4l2_subdev_pad_config *config;
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030068 struct v4l2_mbus_framefmt *format;
Laurent Pincharte5ad37b2013-08-24 20:49:58 -030069 struct v4l2_rect *crop;
Laurent Pinchart34e77ed2016-06-26 08:09:31 -030070 int ret = 0;
71
72 mutex_lock(&rwpf->entity.lock);
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030073
Laurent Pincharte790c3c2015-11-15 19:14:22 -020074 config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which);
Laurent Pinchart34e77ed2016-06-26 08:09:31 -030075 if (!config) {
76 ret = -EINVAL;
77 goto done;
78 }
Laurent Pincharte790c3c2015-11-15 19:14:22 -020079
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030080 /* Default to YUV if the requested format is not supported. */
Boris BREZILLON27ffaeb2014-11-10 14:28:31 -030081 if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
82 fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
83 fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030084
Laurent Pincharte790c3c2015-11-15 19:14:22 -020085 format = vsp1_entity_get_pad_format(&rwpf->entity, config, fmt->pad);
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030086
87 if (fmt->pad == RWPF_PAD_SOURCE) {
88 /* The RWPF performs format conversion but can't scale, only the
89 * format code can be changed on the source pad.
90 */
91 format->code = fmt->format.code;
92 fmt->format = *format;
Laurent Pinchart34e77ed2016-06-26 08:09:31 -030093 goto done;
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030094 }
95
96 format->code = fmt->format.code;
97 format->width = clamp_t(unsigned int, fmt->format.width,
98 RWPF_MIN_WIDTH, rwpf->max_width);
99 format->height = clamp_t(unsigned int, fmt->format.height,
100 RWPF_MIN_HEIGHT, rwpf->max_height);
101 format->field = V4L2_FIELD_NONE;
102 format->colorspace = V4L2_COLORSPACE_SRGB;
103
104 fmt->format = *format;
105
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300106 /* Update the sink crop rectangle. */
Laurent Pinchartb7e51072015-11-15 19:14:22 -0200107 crop = vsp1_rwpf_get_crop(rwpf, config);
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300108 crop->left = 0;
109 crop->top = 0;
110 crop->width = fmt->format.width;
111 crop->height = fmt->format.height;
112
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300113 /* Propagate the format to the source pad. */
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200114 format = vsp1_entity_get_pad_format(&rwpf->entity, config,
115 RWPF_PAD_SOURCE);
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300116 *format = fmt->format;
117
Laurent Pinchart34e77ed2016-06-26 08:09:31 -0300118done:
119 mutex_unlock(&rwpf->entity.lock);
120 return ret;
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300121}
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300122
Laurent Pinchartc6c8efb2015-11-22 13:37:45 -0200123static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
124 struct v4l2_subdev_pad_config *cfg,
125 struct v4l2_subdev_selection *sel)
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300126{
127 struct vsp1_rwpf *rwpf = to_rwpf(subdev);
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200128 struct v4l2_subdev_pad_config *config;
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300129 struct v4l2_mbus_framefmt *format;
Laurent Pinchart34e77ed2016-06-26 08:09:31 -0300130 int ret = 0;
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300131
132 /* Cropping is implemented on the sink pad. */
133 if (sel->pad != RWPF_PAD_SINK)
134 return -EINVAL;
135
Laurent Pinchart34e77ed2016-06-26 08:09:31 -0300136 mutex_lock(&rwpf->entity.lock);
137
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200138 config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
Laurent Pinchart34e77ed2016-06-26 08:09:31 -0300139 if (!config) {
140 ret = -EINVAL;
141 goto done;
142 }
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200143
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300144 switch (sel->target) {
145 case V4L2_SEL_TGT_CROP:
Laurent Pinchartb7e51072015-11-15 19:14:22 -0200146 sel->r = *vsp1_rwpf_get_crop(rwpf, config);
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300147 break;
148
149 case V4L2_SEL_TGT_CROP_BOUNDS:
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200150 format = vsp1_entity_get_pad_format(&rwpf->entity, config,
151 RWPF_PAD_SINK);
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300152 sel->r.left = 0;
153 sel->r.top = 0;
154 sel->r.width = format->width;
155 sel->r.height = format->height;
156 break;
157
158 default:
Laurent Pinchart34e77ed2016-06-26 08:09:31 -0300159 ret = -EINVAL;
160 break;
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300161 }
162
Laurent Pinchart34e77ed2016-06-26 08:09:31 -0300163done:
164 mutex_unlock(&rwpf->entity.lock);
165 return ret;
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300166}
167
Laurent Pinchartc6c8efb2015-11-22 13:37:45 -0200168static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
169 struct v4l2_subdev_pad_config *cfg,
170 struct v4l2_subdev_selection *sel)
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300171{
172 struct vsp1_rwpf *rwpf = to_rwpf(subdev);
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200173 struct v4l2_subdev_pad_config *config;
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300174 struct v4l2_mbus_framefmt *format;
175 struct v4l2_rect *crop;
Laurent Pinchart34e77ed2016-06-26 08:09:31 -0300176 int ret = 0;
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300177
178 /* Cropping is implemented on the sink pad. */
179 if (sel->pad != RWPF_PAD_SINK)
180 return -EINVAL;
181
182 if (sel->target != V4L2_SEL_TGT_CROP)
183 return -EINVAL;
184
Laurent Pinchart34e77ed2016-06-26 08:09:31 -0300185 mutex_lock(&rwpf->entity.lock);
186
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200187 config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
Laurent Pinchart34e77ed2016-06-26 08:09:31 -0300188 if (!config) {
189 ret = -EINVAL;
190 goto done;
191 }
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200192
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300193 /* Make sure the crop rectangle is entirely contained in the image. The
194 * WPF top and left offsets are limited to 255.
195 */
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200196 format = vsp1_entity_get_pad_format(&rwpf->entity, config,
197 RWPF_PAD_SINK);
Damian Hobson-Garcia85a06382015-05-28 09:59:39 -0300198
199 /* Restrict the crop rectangle coordinates to multiples of 2 to avoid
200 * shifting the color plane.
201 */
202 if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) {
203 sel->r.left = ALIGN(sel->r.left, 2);
204 sel->r.top = ALIGN(sel->r.top, 2);
205 sel->r.width = round_down(sel->r.width, 2);
206 sel->r.height = round_down(sel->r.height, 2);
207 }
208
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300209 sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2);
210 sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2);
211 if (rwpf->entity.type == VSP1_ENTITY_WPF) {
212 sel->r.left = min_t(unsigned int, sel->r.left, 255);
213 sel->r.top = min_t(unsigned int, sel->r.top, 255);
214 }
215 sel->r.width = min_t(unsigned int, sel->r.width,
216 format->width - sel->r.left);
217 sel->r.height = min_t(unsigned int, sel->r.height,
218 format->height - sel->r.top);
219
Laurent Pinchartb7e51072015-11-15 19:14:22 -0200220 crop = vsp1_rwpf_get_crop(rwpf, config);
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300221 *crop = sel->r;
222
223 /* Propagate the format to the source pad. */
Laurent Pincharte790c3c2015-11-15 19:14:22 -0200224 format = vsp1_entity_get_pad_format(&rwpf->entity, config,
225 RWPF_PAD_SOURCE);
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300226 format->width = crop->width;
227 format->height = crop->height;
228
Laurent Pinchart34e77ed2016-06-26 08:09:31 -0300229done:
230 mutex_unlock(&rwpf->entity.lock);
231 return ret;
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300232}
Laurent Pinchartbd2fdd52015-11-01 12:19:42 -0200233
Laurent Pinchartc6c8efb2015-11-22 13:37:45 -0200234const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = {
235 .init_cfg = vsp1_entity_init_cfg,
236 .enum_mbus_code = vsp1_rwpf_enum_mbus_code,
237 .enum_frame_size = vsp1_rwpf_enum_frame_size,
Laurent Pinchart3f557222016-02-24 21:10:13 -0300238 .get_fmt = vsp1_subdev_get_pad_format,
Laurent Pinchartc6c8efb2015-11-22 13:37:45 -0200239 .set_fmt = vsp1_rwpf_set_format,
240 .get_selection = vsp1_rwpf_get_selection,
241 .set_selection = vsp1_rwpf_set_selection,
242};
243
Laurent Pinchartbd2fdd52015-11-01 12:19:42 -0200244/* -----------------------------------------------------------------------------
245 * Controls
246 */
247
248static int vsp1_rwpf_s_ctrl(struct v4l2_ctrl *ctrl)
249{
250 struct vsp1_rwpf *rwpf =
251 container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
252
253 switch (ctrl->id) {
254 case V4L2_CID_ALPHA_COMPONENT:
255 rwpf->alpha = ctrl->val;
256 break;
257 }
258
259 return 0;
260}
261
262static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {
263 .s_ctrl = vsp1_rwpf_s_ctrl,
264};
265
Laurent Pinchart894dde52016-05-26 05:14:22 -0300266int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols)
Laurent Pinchartbd2fdd52015-11-01 12:19:42 -0200267{
Laurent Pinchart894dde52016-05-26 05:14:22 -0300268 v4l2_ctrl_handler_init(&rwpf->ctrls, ncontrols + 1);
Laurent Pinchartbd2fdd52015-11-01 12:19:42 -0200269 v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops,
270 V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
271
272 rwpf->entity.subdev.ctrl_handler = &rwpf->ctrls;
273
274 return rwpf->ctrls.error;
275}