aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/vimc
diff options
context:
space:
mode:
authorHelen Fornazier <helen.koike@collabora.com>2017-06-19 13:00:16 -0400
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2017-06-23 08:07:15 -0400
commit88ad71aab1a7931ac3d35c3acaa431c3dc05afd9 (patch)
tree0a0d0be75d70ff503c63888fb1c78c6532373f9c /drivers/media/platform/vimc
parent441c0db6e5a2f07f91b72e31a22a19180d28ebf5 (diff)
[media] vimc: sen: Support several image formats
Allow user space to change the image format as the frame size, the media bus pixel format, colorspace, quantization, field YCbCr encoding and the transfer function Signed-off-by: Helen Koike <helen.koike@collabora.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/platform/vimc')
-rw-r--r--drivers/media/platform/vimc/vimc-common.c8
-rw-r--r--drivers/media/platform/vimc/vimc-common.h12
-rw-r--r--drivers/media/platform/vimc/vimc-sensor.c130
3 files changed, 121 insertions, 29 deletions
diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c
index 6ad77fdc04ad..b69805574c67 100644
--- a/drivers/media/platform/vimc/vimc-common.c
+++ b/drivers/media/platform/vimc/vimc-common.c
@@ -144,6 +144,14 @@ static const struct vimc_pix_map vimc_pix_map_list[] = {
144 }, 144 },
145}; 145};
146 146
147const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)
148{
149 if (i >= ARRAY_SIZE(vimc_pix_map_list))
150 return NULL;
151
152 return &vimc_pix_map_list[i];
153}
154
147const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) 155const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
148{ 156{
149 unsigned int i; 157 unsigned int i;
diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h
index 43483eecb116..fb3463c06185 100644
--- a/drivers/media/platform/vimc/vimc-common.h
+++ b/drivers/media/platform/vimc/vimc-common.h
@@ -22,6 +22,11 @@
22#include <media/media-device.h> 22#include <media/media-device.h>
23#include <media/v4l2-device.h> 23#include <media/v4l2-device.h>
24 24
25#define VIMC_FRAME_MAX_WIDTH 4096
26#define VIMC_FRAME_MAX_HEIGHT 2160
27#define VIMC_FRAME_MIN_WIDTH 16
28#define VIMC_FRAME_MIN_HEIGHT 16
29
25/** 30/**
26 * struct vimc_colorimetry_clamp - Adjust colorimetry parameters 31 * struct vimc_colorimetry_clamp - Adjust colorimetry parameters
27 * 32 *
@@ -139,6 +144,13 @@ static inline void vimc_pads_cleanup(struct media_pad *pads)
139int vimc_pipeline_s_stream(struct media_entity *ent, int enable); 144int vimc_pipeline_s_stream(struct media_entity *ent, int enable);
140 145
141/** 146/**
147 * vimc_pix_map_by_index - get vimc_pix_map struct by its index
148 *
149 * @i: index of the vimc_pix_map struct in vimc_pix_map_list
150 */
151const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i);
152
153/**
142 * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code 154 * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code
143 * 155 *
144 * @code: media bus format code defined by MEDIA_BUS_FMT_* macros 156 * @code: media bus format code defined by MEDIA_BUS_FMT_* macros
diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c
index 6386ac12856c..d4f97050b544 100644
--- a/drivers/media/platform/vimc/vimc-sensor.c
+++ b/drivers/media/platform/vimc/vimc-sensor.c
@@ -24,8 +24,6 @@
24 24
25#include "vimc-sensor.h" 25#include "vimc-sensor.h"
26 26
27#define VIMC_SEN_FRAME_MAX_WIDTH 4096
28
29struct vimc_sen_device { 27struct vimc_sen_device {
30 struct vimc_ent_device ved; 28 struct vimc_ent_device ved;
31 struct v4l2_subdev sd; 29 struct v4l2_subdev sd;
@@ -36,18 +34,39 @@ struct vimc_sen_device {
36 struct v4l2_mbus_framefmt mbus_format; 34 struct v4l2_mbus_framefmt mbus_format;
37}; 35};
38 36
37static const struct v4l2_mbus_framefmt fmt_default = {
38 .width = 640,
39 .height = 480,
40 .code = MEDIA_BUS_FMT_RGB888_1X24,
41 .field = V4L2_FIELD_NONE,
42 .colorspace = V4L2_COLORSPACE_DEFAULT,
43};
44
45static int vimc_sen_init_cfg(struct v4l2_subdev *sd,
46 struct v4l2_subdev_pad_config *cfg)
47{
48 unsigned int i;
49
50 for (i = 0; i < sd->entity.num_pads; i++) {
51 struct v4l2_mbus_framefmt *mf;
52
53 mf = v4l2_subdev_get_try_format(sd, cfg, i);
54 *mf = fmt_default;
55 }
56
57 return 0;
58}
59
39static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, 60static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd,
40 struct v4l2_subdev_pad_config *cfg, 61 struct v4l2_subdev_pad_config *cfg,
41 struct v4l2_subdev_mbus_code_enum *code) 62 struct v4l2_subdev_mbus_code_enum *code)
42{ 63{
43 struct vimc_sen_device *vsen = 64 const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index);
44 container_of(sd, struct vimc_sen_device, sd);
45 65
46 /* TODO: Add support for other codes */ 66 if (!vpix)
47 if (code->index)
48 return -EINVAL; 67 return -EINVAL;
49 68
50 code->code = vsen->mbus_format.code; 69 code->code = vpix->code;
51 70
52 return 0; 71 return 0;
53} 72}
@@ -56,33 +75,34 @@ static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd,
56 struct v4l2_subdev_pad_config *cfg, 75 struct v4l2_subdev_pad_config *cfg,
57 struct v4l2_subdev_frame_size_enum *fse) 76 struct v4l2_subdev_frame_size_enum *fse)
58{ 77{
59 struct vimc_sen_device *vsen = 78 const struct vimc_pix_map *vpix;
60 container_of(sd, struct vimc_sen_device, sd);
61 79
62 /* TODO: Add support to other formats */
63 if (fse->index) 80 if (fse->index)
64 return -EINVAL; 81 return -EINVAL;
65 82
66 /* TODO: Add support for other codes */ 83 /* Only accept code in the pix map table */
67 if (fse->code != vsen->mbus_format.code) 84 vpix = vimc_pix_map_by_code(fse->code);
85 if (!vpix)
68 return -EINVAL; 86 return -EINVAL;
69 87
70 fse->min_width = vsen->mbus_format.width; 88 fse->min_width = VIMC_FRAME_MIN_WIDTH;
71 fse->max_width = vsen->mbus_format.width; 89 fse->max_width = VIMC_FRAME_MAX_WIDTH;
72 fse->min_height = vsen->mbus_format.height; 90 fse->min_height = VIMC_FRAME_MIN_HEIGHT;
73 fse->max_height = vsen->mbus_format.height; 91 fse->max_height = VIMC_FRAME_MAX_HEIGHT;
74 92
75 return 0; 93 return 0;
76} 94}
77 95
78static int vimc_sen_get_fmt(struct v4l2_subdev *sd, 96static int vimc_sen_get_fmt(struct v4l2_subdev *sd,
79 struct v4l2_subdev_pad_config *cfg, 97 struct v4l2_subdev_pad_config *cfg,
80 struct v4l2_subdev_format *format) 98 struct v4l2_subdev_format *fmt)
81{ 99{
82 struct vimc_sen_device *vsen = 100 struct vimc_sen_device *vsen =
83 container_of(sd, struct vimc_sen_device, sd); 101 container_of(sd, struct vimc_sen_device, sd);
84 102
85 format->format = vsen->mbus_format; 103 fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
104 *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) :
105 vsen->mbus_format;
86 106
87 return 0; 107 return 0;
88} 108}
@@ -105,12 +125,70 @@ static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen)
105 tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func); 125 tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func);
106} 126}
107 127
128static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
129{
130 const struct vimc_pix_map *vpix;
131
132 /* Only accept code in the pix map table */
133 vpix = vimc_pix_map_by_code(fmt->code);
134 if (!vpix)
135 fmt->code = fmt_default.code;
136
137 fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH,
138 VIMC_FRAME_MAX_WIDTH) & ~1;
139 fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT,
140 VIMC_FRAME_MAX_HEIGHT) & ~1;
141
142 /* TODO: add support for V4L2_FIELD_ALTERNATE */
143 if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE)
144 fmt->field = fmt_default.field;
145
146 vimc_colorimetry_clamp(fmt);
147}
148
149static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
150 struct v4l2_subdev_pad_config *cfg,
151 struct v4l2_subdev_format *fmt)
152{
153 struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd);
154 struct v4l2_mbus_framefmt *mf;
155
156 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
157 /* Do not change the format while stream is on */
158 if (vsen->frame)
159 return -EBUSY;
160
161 mf = &vsen->mbus_format;
162 } else {
163 mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
164 }
165
166 /* Set the new format */
167 vimc_sen_adjust_fmt(&fmt->format);
168
169 dev_dbg(vsen->sd.v4l2_dev->mdev->dev, "%s: format update: "
170 "old:%dx%d (0x%x, %d, %d, %d, %d) "
171 "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name,
172 /* old */
173 mf->width, mf->height, mf->code,
174 mf->colorspace, mf->quantization,
175 mf->xfer_func, mf->ycbcr_enc,
176 /* new */
177 fmt->format.width, fmt->format.height, fmt->format.code,
178 fmt->format.colorspace, fmt->format.quantization,
179 fmt->format.xfer_func, fmt->format.ycbcr_enc);
180
181 *mf = fmt->format;
182
183 return 0;
184}
185
108static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { 186static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = {
187 .init_cfg = vimc_sen_init_cfg,
109 .enum_mbus_code = vimc_sen_enum_mbus_code, 188 .enum_mbus_code = vimc_sen_enum_mbus_code,
110 .enum_frame_size = vimc_sen_enum_frame_size, 189 .enum_frame_size = vimc_sen_enum_frame_size,
111 .get_fmt = vimc_sen_get_fmt, 190 .get_fmt = vimc_sen_get_fmt,
112 /* TODO: Add support to other formats */ 191 .set_fmt = vimc_sen_set_fmt,
113 .set_fmt = vimc_sen_get_fmt,
114}; 192};
115 193
116static int vimc_sen_tpg_thread(void *data) 194static int vimc_sen_tpg_thread(void *data)
@@ -247,19 +325,13 @@ struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev,
247 if (ret) 325 if (ret)
248 goto err_free_vsen; 326 goto err_free_vsen;
249 327
250 /* Set the active frame format (this is hardcoded for now) */ 328 /* Initialize the frame format */
251 vsen->mbus_format.width = 640; 329 vsen->mbus_format = fmt_default;
252 vsen->mbus_format.height = 480;
253 vsen->mbus_format.code = MEDIA_BUS_FMT_RGB888_1X24;
254 vsen->mbus_format.field = V4L2_FIELD_NONE;
255 vsen->mbus_format.colorspace = V4L2_COLORSPACE_SRGB;
256 vsen->mbus_format.quantization = V4L2_QUANTIZATION_FULL_RANGE;
257 vsen->mbus_format.xfer_func = V4L2_XFER_FUNC_SRGB;
258 330
259 /* Initialize the test pattern generator */ 331 /* Initialize the test pattern generator */
260 tpg_init(&vsen->tpg, vsen->mbus_format.width, 332 tpg_init(&vsen->tpg, vsen->mbus_format.width,
261 vsen->mbus_format.height); 333 vsen->mbus_format.height);
262 ret = tpg_alloc(&vsen->tpg, VIMC_SEN_FRAME_MAX_WIDTH); 334 ret = tpg_alloc(&vsen->tpg, VIMC_FRAME_MAX_WIDTH);
263 if (ret) 335 if (ret)
264 goto err_unregister_ent_sd; 336 goto err_unregister_ent_sd;
265 337