blob: 8aa8c111301ca670ef382f315b0092aa0ae2ef07 [file] [log] [blame]
Laurent Pinchart989af882013-07-10 12:03:30 -03001/*
2 * vsp1_lut.c -- R-Car VSP1 Look-Up Table
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#include <linux/vsp1.h>
17
18#include <media/v4l2-subdev.h>
19
20#include "vsp1.h"
21#include "vsp1_lut.h"
22
23#define LUT_MIN_SIZE 4U
24#define LUT_MAX_SIZE 8190U
25
26/* -----------------------------------------------------------------------------
27 * Device Access
28 */
29
30static inline u32 vsp1_lut_read(struct vsp1_lut *lut, u32 reg)
31{
32 return vsp1_read(lut->entity.vsp1, reg);
33}
34
35static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
36{
37 vsp1_write(lut->entity.vsp1, reg, data);
38}
39
40/* -----------------------------------------------------------------------------
41 * V4L2 Subdevice Core Operations
42 */
43
44static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config)
45{
46 memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut,
47 sizeof(config->lut));
48}
49
50static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
51{
52 struct vsp1_lut *lut = to_lut(subdev);
53
54 switch (cmd) {
55 case VIDIOC_VSP1_LUT_CONFIG:
56 lut_configure(lut, arg);
57 return 0;
58
59 default:
60 return -ENOIOCTLCMD;
61 }
62}
63
64/* -----------------------------------------------------------------------------
65 * V4L2 Subdevice Video Operations
66 */
67
68static int lut_s_stream(struct v4l2_subdev *subdev, int enable)
69{
70 struct vsp1_lut *lut = to_lut(subdev);
71
72 if (!enable)
73 return 0;
74
75 vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
76
77 return 0;
78}
79
80/* -----------------------------------------------------------------------------
81 * V4L2 Subdevice Pad Operations
82 */
83
84static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
Hans Verkuilf7234132015-03-04 01:47:54 -080085 struct v4l2_subdev_pad_config *cfg,
Laurent Pinchart989af882013-07-10 12:03:30 -030086 struct v4l2_subdev_mbus_code_enum *code)
87{
88 static const unsigned int codes[] = {
Boris BREZILLON27ffaeb2014-11-10 14:28:31 -030089 MEDIA_BUS_FMT_ARGB8888_1X32,
90 MEDIA_BUS_FMT_AHSV8888_1X32,
91 MEDIA_BUS_FMT_AYUV8_1X32,
Laurent Pinchart989af882013-07-10 12:03:30 -030092 };
Hans Verkuil3f1ccf12015-03-04 01:47:57 -080093 struct vsp1_lut *lut = to_lut(subdev);
Laurent Pinchart989af882013-07-10 12:03:30 -030094 struct v4l2_mbus_framefmt *format;
95
96 if (code->pad == LUT_PAD_SINK) {
97 if (code->index >= ARRAY_SIZE(codes))
98 return -EINVAL;
99
100 code->code = codes[code->index];
101 } else {
102 /* The LUT can't perform format conversion, the sink format is
103 * always identical to the source format.
104 */
105 if (code->index)
106 return -EINVAL;
107
Hans Verkuil3f1ccf12015-03-04 01:47:57 -0800108 format = vsp1_entity_get_pad_format(&lut->entity, cfg,
109 LUT_PAD_SINK, code->which);
Laurent Pinchart989af882013-07-10 12:03:30 -0300110 code->code = format->code;
111 }
112
113 return 0;
114}
115
116static int lut_enum_frame_size(struct v4l2_subdev *subdev,
Hans Verkuilf7234132015-03-04 01:47:54 -0800117 struct v4l2_subdev_pad_config *cfg,
Laurent Pinchart989af882013-07-10 12:03:30 -0300118 struct v4l2_subdev_frame_size_enum *fse)
119{
120 struct v4l2_mbus_framefmt *format;
121
Hans Verkuilf7234132015-03-04 01:47:54 -0800122 format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
Laurent Pinchart989af882013-07-10 12:03:30 -0300123
124 if (fse->index || fse->code != format->code)
125 return -EINVAL;
126
127 if (fse->pad == LUT_PAD_SINK) {
128 fse->min_width = LUT_MIN_SIZE;
129 fse->max_width = LUT_MAX_SIZE;
130 fse->min_height = LUT_MIN_SIZE;
131 fse->max_height = LUT_MAX_SIZE;
132 } else {
133 /* The size on the source pad are fixed and always identical to
134 * the size on the sink pad.
135 */
136 fse->min_width = format->width;
137 fse->max_width = format->width;
138 fse->min_height = format->height;
139 fse->max_height = format->height;
140 }
141
142 return 0;
143}
144
Hans Verkuilf7234132015-03-04 01:47:54 -0800145static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
Laurent Pinchart989af882013-07-10 12:03:30 -0300146 struct v4l2_subdev_format *fmt)
147{
148 struct vsp1_lut *lut = to_lut(subdev);
149
Hans Verkuilf7234132015-03-04 01:47:54 -0800150 fmt->format = *vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad,
Laurent Pinchart989af882013-07-10 12:03:30 -0300151 fmt->which);
152
153 return 0;
154}
155
Hans Verkuilf7234132015-03-04 01:47:54 -0800156static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
Laurent Pinchart989af882013-07-10 12:03:30 -0300157 struct v4l2_subdev_format *fmt)
158{
159 struct vsp1_lut *lut = to_lut(subdev);
160 struct v4l2_mbus_framefmt *format;
161
162 /* Default to YUV if the requested format is not supported. */
Boris BREZILLON27ffaeb2014-11-10 14:28:31 -0300163 if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
164 fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 &&
165 fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
166 fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
Laurent Pinchart989af882013-07-10 12:03:30 -0300167
Hans Verkuilf7234132015-03-04 01:47:54 -0800168 format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad,
Laurent Pinchart989af882013-07-10 12:03:30 -0300169 fmt->which);
170
171 if (fmt->pad == LUT_PAD_SOURCE) {
172 /* The LUT output format can't be modified. */
173 fmt->format = *format;
174 return 0;
175 }
176
177 format->width = clamp_t(unsigned int, fmt->format.width,
178 LUT_MIN_SIZE, LUT_MAX_SIZE);
179 format->height = clamp_t(unsigned int, fmt->format.height,
180 LUT_MIN_SIZE, LUT_MAX_SIZE);
181 format->field = V4L2_FIELD_NONE;
182 format->colorspace = V4L2_COLORSPACE_SRGB;
183
184 fmt->format = *format;
185
186 /* Propagate the format to the source pad. */
Hans Verkuilf7234132015-03-04 01:47:54 -0800187 format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE,
Laurent Pinchart989af882013-07-10 12:03:30 -0300188 fmt->which);
189 *format = fmt->format;
190
191 return 0;
192}
193
194/* -----------------------------------------------------------------------------
195 * V4L2 Subdevice Operations
196 */
197
198static struct v4l2_subdev_core_ops lut_core_ops = {
199 .ioctl = lut_ioctl,
200};
201
202static struct v4l2_subdev_video_ops lut_video_ops = {
203 .s_stream = lut_s_stream,
204};
205
206static struct v4l2_subdev_pad_ops lut_pad_ops = {
207 .enum_mbus_code = lut_enum_mbus_code,
208 .enum_frame_size = lut_enum_frame_size,
209 .get_fmt = lut_get_format,
210 .set_fmt = lut_set_format,
211};
212
213static struct v4l2_subdev_ops lut_ops = {
214 .core = &lut_core_ops,
215 .video = &lut_video_ops,
216 .pad = &lut_pad_ops,
217};
218
219/* -----------------------------------------------------------------------------
220 * Initialization and Cleanup
221 */
222
223struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
224{
225 struct v4l2_subdev *subdev;
226 struct vsp1_lut *lut;
227 int ret;
228
229 lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL);
230 if (lut == NULL)
231 return ERR_PTR(-ENOMEM);
232
233 lut->entity.type = VSP1_ENTITY_LUT;
Laurent Pinchart989af882013-07-10 12:03:30 -0300234
235 ret = vsp1_entity_init(vsp1, &lut->entity, 2);
236 if (ret < 0)
237 return ERR_PTR(ret);
238
239 /* Initialize the V4L2 subdev. */
240 subdev = &lut->entity.subdev;
241 v4l2_subdev_init(subdev, &lut_ops);
242
243 subdev->entity.ops = &vsp1_media_ops;
244 subdev->internal_ops = &vsp1_subdev_internal_ops;
245 snprintf(subdev->name, sizeof(subdev->name), "%s lut",
246 dev_name(vsp1->dev));
247 v4l2_set_subdevdata(subdev, lut);
248 subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
249
250 vsp1_entity_init_formats(subdev, NULL);
251
252 return lut;
253}