1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Driver for STM32 Digital Camera Memory Interface Pixel Processor
4 *
5 * Copyright (C) STMicroelectronics SA 2023
6 * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com>
7 * Alain Volmat <alain.volmat@foss.st.com>
8 * for STMicroelectronics.
9 */
10
11 #include <linux/vmalloc.h>
12 #include <linux/v4l2-mediabus.h>
13 #include <media/v4l2-rect.h>
14 #include <media/v4l2-subdev.h>
15
16 #include "dcmipp-common.h"
17
18 #define DCMIPP_P0FCTCR 0x500
19 #define DCMIPP_P0FCTCR_FRATE_MASK GENMASK(1, 0)
20 #define DCMIPP_P0SCSTR 0x504
21 #define DCMIPP_P0SCSTR_HSTART_SHIFT 0
22 #define DCMIPP_P0SCSTR_VSTART_SHIFT 16
23 #define DCMIPP_P0SCSZR 0x508
24 #define DCMIPP_P0SCSZR_ENABLE BIT(31)
25 #define DCMIPP_P0SCSZR_HSIZE_SHIFT 0
26 #define DCMIPP_P0SCSZR_VSIZE_SHIFT 16
27 #define DCMIPP_P0PPCR 0x5c0
28 #define DCMIPP_P0PPCR_BSM_1_2 0x1
29 #define DCMIPP_P0PPCR_BSM_1_4 0x2
30 #define DCMIPP_P0PPCR_BSM_2_4 0x3
31 #define DCMIPP_P0PPCR_BSM_MASK GENMASK(8, 7)
32 #define DCMIPP_P0PPCR_BSM_SHIFT 0x7
33 #define DCMIPP_P0PPCR_LSM BIT(10)
34 #define DCMIPP_P0PPCR_OELS BIT(11)
35
36 #define IS_SINK(pad) (!(pad))
37 #define IS_SRC(pad) ((pad))
38
39 struct dcmipp_byteproc_pix_map {
40 unsigned int code;
41 unsigned int bpp;
42 };
43
44 #define PIXMAP_MBUS_BPP(mbus, byteperpixel) \
45 { \
46 .code = MEDIA_BUS_FMT_##mbus, \
47 .bpp = byteperpixel, \
48 }
49 static const struct dcmipp_byteproc_pix_map dcmipp_byteproc_pix_map_list[] = {
50 PIXMAP_MBUS_BPP(RGB565_2X8_LE, 2),
51 PIXMAP_MBUS_BPP(RGB565_1X16, 2),
52 PIXMAP_MBUS_BPP(RGB888_3X8, 3),
53 PIXMAP_MBUS_BPP(RGB888_1X24, 3),
54 PIXMAP_MBUS_BPP(YUYV8_2X8, 2),
55 PIXMAP_MBUS_BPP(YUYV8_1X16, 2),
56 PIXMAP_MBUS_BPP(YVYU8_2X8, 2),
57 PIXMAP_MBUS_BPP(YVYU8_1X16, 2),
58 PIXMAP_MBUS_BPP(UYVY8_2X8, 2),
59 PIXMAP_MBUS_BPP(UYVY8_1X16, 2),
60 PIXMAP_MBUS_BPP(VYUY8_2X8, 2),
61 PIXMAP_MBUS_BPP(VYUY8_1X16, 2),
62 PIXMAP_MBUS_BPP(Y8_1X8, 1),
63 PIXMAP_MBUS_BPP(Y10_1X10, 2),
64 PIXMAP_MBUS_BPP(Y12_1X12, 2),
65 PIXMAP_MBUS_BPP(Y14_1X14, 2),
66 PIXMAP_MBUS_BPP(SBGGR8_1X8, 1),
67 PIXMAP_MBUS_BPP(SGBRG8_1X8, 1),
68 PIXMAP_MBUS_BPP(SGRBG8_1X8, 1),
69 PIXMAP_MBUS_BPP(SRGGB8_1X8, 1),
70 PIXMAP_MBUS_BPP(SBGGR10_1X10, 2),
71 PIXMAP_MBUS_BPP(SGBRG10_1X10, 2),
72 PIXMAP_MBUS_BPP(SGRBG10_1X10, 2),
73 PIXMAP_MBUS_BPP(SRGGB10_1X10, 2),
74 PIXMAP_MBUS_BPP(SBGGR12_1X12, 2),
75 PIXMAP_MBUS_BPP(SGBRG12_1X12, 2),
76 PIXMAP_MBUS_BPP(SGRBG12_1X12, 2),
77 PIXMAP_MBUS_BPP(SRGGB12_1X12, 2),
78 PIXMAP_MBUS_BPP(SBGGR14_1X14, 2),
79 PIXMAP_MBUS_BPP(SGBRG14_1X14, 2),
80 PIXMAP_MBUS_BPP(SGRBG14_1X14, 2),
81 PIXMAP_MBUS_BPP(SRGGB14_1X14, 2),
82 PIXMAP_MBUS_BPP(JPEG_1X8, 1),
83 };
84
85 static const struct dcmipp_byteproc_pix_map *
dcmipp_byteproc_pix_map_by_code(u32 code)86 dcmipp_byteproc_pix_map_by_code(u32 code)
87 {
88 unsigned int i;
89
90 for (i = 0; i < ARRAY_SIZE(dcmipp_byteproc_pix_map_list); i++) {
91 if (dcmipp_byteproc_pix_map_list[i].code == code)
92 return &dcmipp_byteproc_pix_map_list[i];
93 }
94
95 return NULL;
96 }
97
98 struct dcmipp_byteproc_device {
99 struct dcmipp_ent_device ved;
100 struct v4l2_subdev sd;
101 struct device *dev;
102 void __iomem *regs;
103 };
104
105 static const struct v4l2_mbus_framefmt fmt_default = {
106 .width = DCMIPP_FMT_WIDTH_DEFAULT,
107 .height = DCMIPP_FMT_HEIGHT_DEFAULT,
108 .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
109 .field = V4L2_FIELD_NONE,
110 .colorspace = DCMIPP_COLORSPACE_DEFAULT,
111 .ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT,
112 .quantization = DCMIPP_QUANTIZATION_DEFAULT,
113 .xfer_func = DCMIPP_XFER_FUNC_DEFAULT,
114 };
115
116 static const struct v4l2_rect crop_min = {
117 .width = DCMIPP_FRAME_MIN_WIDTH,
118 .height = DCMIPP_FRAME_MIN_HEIGHT,
119 .top = 0,
120 .left = 0,
121 };
122
dcmipp_byteproc_adjust_crop(struct v4l2_rect * r,struct v4l2_rect * compose)123 static void dcmipp_byteproc_adjust_crop(struct v4l2_rect *r,
124 struct v4l2_rect *compose)
125 {
126 /* Disallow rectangles smaller than the minimal one. */
127 v4l2_rect_set_min_size(r, &crop_min);
128 v4l2_rect_map_inside(r, compose);
129 }
130
dcmipp_byteproc_adjust_compose(struct v4l2_rect * r,const struct v4l2_mbus_framefmt * fmt)131 static void dcmipp_byteproc_adjust_compose(struct v4l2_rect *r,
132 const struct v4l2_mbus_framefmt *fmt)
133 {
134 const struct dcmipp_byteproc_pix_map *vpix;
135
136 r->top = 0;
137 r->left = 0;
138
139 /* Compose is not possible for JPEG or Bayer formats */
140 if (fmt->code >= MEDIA_BUS_FMT_SBGGR8_1X8 &&
141 fmt->code <= MEDIA_BUS_FMT_JPEG_1X8) {
142 r->width = fmt->width;
143 r->height = fmt->height;
144 return;
145 }
146
147 /* Prevent compose on formats which are not 1 or 2 bytes per pixel */
148 vpix = dcmipp_byteproc_pix_map_by_code(fmt->code);
149 if (vpix->bpp != 1 && vpix->bpp != 2) {
150 r->width = fmt->width;
151 r->height = fmt->height;
152 return;
153 }
154
155 /* Adjust height - we can only perform 1/2 decimation */
156 if (r->height <= (fmt->height / 2))
157 r->height = fmt->height / 2;
158 else
159 r->height = fmt->height;
160
161 /* Adjust width /2 or /4 for 8bits formats and /2 for 16bits formats */
162 if (vpix->bpp == 1 && r->width <= (fmt->width / 4))
163 r->width = fmt->width / 4;
164 else if (r->width <= (fmt->width / 2))
165 r->width = fmt->width / 2;
166 else
167 r->width = fmt->width;
168 }
169
dcmipp_byteproc_adjust_fmt(struct v4l2_mbus_framefmt * fmt)170 static void dcmipp_byteproc_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
171 {
172 const struct dcmipp_byteproc_pix_map *vpix;
173
174 /* Only accept code in the pix map table */
175 vpix = dcmipp_byteproc_pix_map_by_code(fmt->code);
176 if (!vpix)
177 fmt->code = fmt_default.code;
178
179 fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH,
180 DCMIPP_FRAME_MAX_WIDTH) & ~1;
181 fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT,
182 DCMIPP_FRAME_MAX_HEIGHT) & ~1;
183
184 if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE)
185 fmt->field = fmt_default.field;
186
187 dcmipp_colorimetry_clamp(fmt);
188 }
189
dcmipp_byteproc_init_state(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)190 static int dcmipp_byteproc_init_state(struct v4l2_subdev *sd,
191 struct v4l2_subdev_state *sd_state)
192 {
193 unsigned int i;
194
195 for (i = 0; i < sd->entity.num_pads; i++) {
196 struct v4l2_mbus_framefmt *mf;
197 struct v4l2_rect *r;
198
199 mf = v4l2_subdev_state_get_format(sd_state, i);
200 *mf = fmt_default;
201
202 if (IS_SINK(i))
203 r = v4l2_subdev_state_get_compose(sd_state, i);
204 else
205 r = v4l2_subdev_state_get_crop(sd_state, i);
206
207 r->top = 0;
208 r->left = 0;
209 r->width = DCMIPP_FMT_WIDTH_DEFAULT;
210 r->height = DCMIPP_FMT_HEIGHT_DEFAULT;
211 }
212
213 return 0;
214 }
215
216 static int
dcmipp_byteproc_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)217 dcmipp_byteproc_enum_mbus_code(struct v4l2_subdev *sd,
218 struct v4l2_subdev_state *sd_state,
219 struct v4l2_subdev_mbus_code_enum *code)
220 {
221 const struct dcmipp_byteproc_pix_map *vpix;
222 struct v4l2_mbus_framefmt *sink_fmt;
223
224 if (IS_SINK(code->pad)) {
225 if (code->index >= ARRAY_SIZE(dcmipp_byteproc_pix_map_list))
226 return -EINVAL;
227 vpix = &dcmipp_byteproc_pix_map_list[code->index];
228 code->code = vpix->code;
229 } else {
230 /* byteproc doesn't support transformation on format */
231 if (code->index > 0)
232 return -EINVAL;
233
234 sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
235 code->code = sink_fmt->code;
236 }
237
238 return 0;
239 }
240
241 static int
dcmipp_byteproc_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)242 dcmipp_byteproc_enum_frame_size(struct v4l2_subdev *sd,
243 struct v4l2_subdev_state *sd_state,
244 struct v4l2_subdev_frame_size_enum *fse)
245 {
246 struct v4l2_rect *compose;
247
248 if (fse->index)
249 return -EINVAL;
250
251 fse->min_width = DCMIPP_FRAME_MIN_WIDTH;
252 fse->min_height = DCMIPP_FRAME_MIN_HEIGHT;
253
254 if (IS_SINK(fse->pad)) {
255 fse->max_width = DCMIPP_FRAME_MAX_WIDTH;
256 fse->max_height = DCMIPP_FRAME_MAX_HEIGHT;
257 } else {
258 compose = v4l2_subdev_state_get_compose(sd_state, 0);
259 fse->max_width = compose->width;
260 fse->max_height = compose->height;
261 }
262
263 return 0;
264 }
265
dcmipp_byteproc_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)266 static int dcmipp_byteproc_set_fmt(struct v4l2_subdev *sd,
267 struct v4l2_subdev_state *sd_state,
268 struct v4l2_subdev_format *fmt)
269 {
270 struct v4l2_mbus_framefmt *mf;
271 struct v4l2_rect *crop, *compose;
272
273 if (v4l2_subdev_is_streaming(sd))
274 return -EBUSY;
275
276 mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
277
278 crop = v4l2_subdev_state_get_crop(sd_state, 1);
279 compose = v4l2_subdev_state_get_compose(sd_state, 0);
280
281 if (IS_SRC(fmt->pad)) {
282 fmt->format = *v4l2_subdev_state_get_format(sd_state, 0);
283 fmt->format.width = crop->width;
284 fmt->format.height = crop->height;
285 } else {
286 dcmipp_byteproc_adjust_fmt(&fmt->format);
287 crop->top = 0;
288 crop->left = 0;
289 crop->width = fmt->format.width;
290 crop->height = fmt->format.height;
291 *compose = *crop;
292 /* Set the same format on SOURCE pad as well */
293 *v4l2_subdev_state_get_format(sd_state, 1) = fmt->format;
294 }
295 *mf = fmt->format;
296
297 return 0;
298 }
299
dcmipp_byteproc_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * s)300 static int dcmipp_byteproc_get_selection(struct v4l2_subdev *sd,
301 struct v4l2_subdev_state *sd_state,
302 struct v4l2_subdev_selection *s)
303 {
304 struct v4l2_mbus_framefmt *sink_fmt;
305 struct v4l2_rect *crop, *compose;
306
307 /*
308 * In the HW, the decimation block is located prior to the crop hence:
309 * Compose is done on the sink pad
310 * Crop is done on the src pad
311 */
312 if (IS_SINK(s->pad) &&
313 (s->target == V4L2_SEL_TGT_CROP ||
314 s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
315 s->target == V4L2_SEL_TGT_CROP_DEFAULT))
316 return -EINVAL;
317
318 if (IS_SRC(s->pad) &&
319 (s->target == V4L2_SEL_TGT_COMPOSE ||
320 s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
321 s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT))
322 return -EINVAL;
323
324 sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
325 crop = v4l2_subdev_state_get_crop(sd_state, 1);
326 compose = v4l2_subdev_state_get_compose(sd_state, 0);
327
328 switch (s->target) {
329 case V4L2_SEL_TGT_CROP:
330 s->r = *crop;
331 break;
332 case V4L2_SEL_TGT_CROP_BOUNDS:
333 case V4L2_SEL_TGT_CROP_DEFAULT:
334 s->r = *compose;
335 break;
336 case V4L2_SEL_TGT_COMPOSE:
337 s->r = *compose;
338 break;
339 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
340 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
341 s->r.top = 0;
342 s->r.left = 0;
343 s->r.width = sink_fmt->width;
344 s->r.height = sink_fmt->height;
345 break;
346 default:
347 return -EINVAL;
348 }
349
350 return 0;
351 }
352
dcmipp_byteproc_set_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * s)353 static int dcmipp_byteproc_set_selection(struct v4l2_subdev *sd,
354 struct v4l2_subdev_state *sd_state,
355 struct v4l2_subdev_selection *s)
356 {
357 struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
358 struct v4l2_mbus_framefmt *mf;
359 struct v4l2_rect *crop, *compose;
360
361 /*
362 * In the HW, the decimation block is located prior to the crop hence:
363 * Compose is done on the sink pad
364 * Crop is done on the src pad
365 */
366 if ((s->target == V4L2_SEL_TGT_CROP ||
367 s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
368 s->target == V4L2_SEL_TGT_CROP_DEFAULT) && IS_SINK(s->pad))
369 return -EINVAL;
370
371 if ((s->target == V4L2_SEL_TGT_COMPOSE ||
372 s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
373 s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT) && IS_SRC(s->pad))
374 return -EINVAL;
375
376 crop = v4l2_subdev_state_get_crop(sd_state, 1);
377 compose = v4l2_subdev_state_get_compose(sd_state, 0);
378
379 switch (s->target) {
380 case V4L2_SEL_TGT_CROP:
381 dcmipp_byteproc_adjust_crop(&s->r, compose);
382
383 *crop = s->r;
384 mf = v4l2_subdev_state_get_format(sd_state, 1);
385 mf->width = s->r.width;
386 mf->height = s->r.height;
387
388 dev_dbg(byteproc->dev, "s_selection: crop (%d,%d)/%ux%u\n",
389 crop->left, crop->top, crop->width, crop->height);
390 break;
391 case V4L2_SEL_TGT_COMPOSE:
392 mf = v4l2_subdev_state_get_format(sd_state, 0);
393 dcmipp_byteproc_adjust_compose(&s->r, mf);
394 *compose = s->r;
395 *crop = s->r;
396
397 mf = v4l2_subdev_state_get_format(sd_state, 1);
398 mf->width = s->r.width;
399 mf->height = s->r.height;
400
401 dev_dbg(byteproc->dev, "s_selection: compose (%d,%d)/%ux%u\n",
402 compose->left, compose->top,
403 compose->width, compose->height);
404 break;
405 default:
406 return -EINVAL;
407 }
408
409 return 0;
410 }
411
dcmipp_byteproc_configure_scale_crop(struct dcmipp_byteproc_device * byteproc,struct v4l2_subdev_state * state)412 static int dcmipp_byteproc_configure_scale_crop
413 (struct dcmipp_byteproc_device *byteproc,
414 struct v4l2_subdev_state *state)
415 {
416 const struct dcmipp_byteproc_pix_map *vpix;
417 struct v4l2_mbus_framefmt *sink_fmt;
418 u32 hprediv, vprediv;
419 struct v4l2_rect *compose, *crop;
420 u32 val = 0;
421
422 sink_fmt = v4l2_subdev_state_get_format(state, 0);
423 compose = v4l2_subdev_state_get_compose(state, 0);
424 crop = v4l2_subdev_state_get_crop(state, 1);
425
426 /* find output format bpp */
427 vpix = dcmipp_byteproc_pix_map_by_code(sink_fmt->code);
428 if (!vpix)
429 return -EINVAL;
430
431 /* clear decimation/crop */
432 reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_BSM_MASK);
433 reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_LSM);
434 reg_write(byteproc, DCMIPP_P0SCSTR, 0);
435 reg_write(byteproc, DCMIPP_P0SCSZR, 0);
436
437 /* Ignore decimation/crop with JPEG */
438 if (vpix->code == MEDIA_BUS_FMT_JPEG_1X8)
439 return 0;
440
441 /* decimation */
442 hprediv = sink_fmt->width / compose->width;
443 if (hprediv == 4)
444 val |= DCMIPP_P0PPCR_BSM_1_4 << DCMIPP_P0PPCR_BSM_SHIFT;
445 else if ((vpix->code == MEDIA_BUS_FMT_Y8_1X8) && (hprediv == 2))
446 val |= DCMIPP_P0PPCR_BSM_1_2 << DCMIPP_P0PPCR_BSM_SHIFT;
447 else if (hprediv == 2)
448 val |= DCMIPP_P0PPCR_BSM_2_4 << DCMIPP_P0PPCR_BSM_SHIFT;
449
450 vprediv = sink_fmt->height / compose->height;
451 if (vprediv == 2)
452 val |= DCMIPP_P0PPCR_LSM | DCMIPP_P0PPCR_OELS;
453
454 /* decimate using bytes and lines skipping */
455 if (val) {
456 reg_set(byteproc, DCMIPP_P0PPCR, val);
457
458 dev_dbg(byteproc->dev, "decimate to %dx%d [prediv=%dx%d]\n",
459 compose->width, compose->height,
460 hprediv, vprediv);
461 }
462
463 dev_dbg(byteproc->dev, "crop to %dx%d\n", crop->width, crop->height);
464
465 /* expressed in 32-bits words on X axis, lines on Y axis */
466 reg_write(byteproc, DCMIPP_P0SCSTR,
467 (((crop->left * vpix->bpp) / 4) <<
468 DCMIPP_P0SCSTR_HSTART_SHIFT) |
469 (crop->top << DCMIPP_P0SCSTR_VSTART_SHIFT));
470 reg_write(byteproc, DCMIPP_P0SCSZR,
471 DCMIPP_P0SCSZR_ENABLE |
472 (((crop->width * vpix->bpp) / 4) <<
473 DCMIPP_P0SCSZR_HSIZE_SHIFT) |
474 (crop->height << DCMIPP_P0SCSZR_VSIZE_SHIFT));
475
476 return 0;
477 }
478
dcmipp_byteproc_enable_streams(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,u32 pad,u64 streams_mask)479 static int dcmipp_byteproc_enable_streams(struct v4l2_subdev *sd,
480 struct v4l2_subdev_state *state,
481 u32 pad, u64 streams_mask)
482 {
483 struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
484 struct v4l2_subdev *s_subdev;
485 struct media_pad *s_pad;
486 int ret;
487
488 /* Get source subdev */
489 s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
490 if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
491 return -EINVAL;
492 s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
493
494 ret = dcmipp_byteproc_configure_scale_crop(byteproc, state);
495 if (ret)
496 return ret;
497
498 ret = v4l2_subdev_enable_streams(s_subdev, s_pad->index, BIT_ULL(0));
499 if (ret < 0) {
500 dev_err(byteproc->dev,
501 "failed to start source subdev streaming (%d)\n", ret);
502 return ret;
503 }
504
505 return 0;
506 }
507
dcmipp_byteproc_disable_streams(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,u32 pad,u64 streams_mask)508 static int dcmipp_byteproc_disable_streams(struct v4l2_subdev *sd,
509 struct v4l2_subdev_state *state,
510 u32 pad, u64 streams_mask)
511 {
512 struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
513 struct v4l2_subdev *s_subdev;
514 struct media_pad *s_pad;
515 int ret;
516
517 /* Get source subdev */
518 s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
519 if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity))
520 return -EINVAL;
521 s_subdev = media_entity_to_v4l2_subdev(s_pad->entity);
522
523 ret = v4l2_subdev_disable_streams(s_subdev, s_pad->index, BIT_ULL(0));
524 if (ret < 0) {
525 dev_err(byteproc->dev,
526 "failed to start source subdev streaming (%d)\n", ret);
527 return ret;
528 }
529
530 return 0;
531 }
532
533 static const struct v4l2_subdev_pad_ops dcmipp_byteproc_pad_ops = {
534 .enum_mbus_code = dcmipp_byteproc_enum_mbus_code,
535 .enum_frame_size = dcmipp_byteproc_enum_frame_size,
536 .get_fmt = v4l2_subdev_get_fmt,
537 .set_fmt = dcmipp_byteproc_set_fmt,
538 .get_selection = dcmipp_byteproc_get_selection,
539 .set_selection = dcmipp_byteproc_set_selection,
540 .enable_streams = dcmipp_byteproc_enable_streams,
541 .disable_streams = dcmipp_byteproc_disable_streams,
542 };
543
544 static const struct v4l2_subdev_video_ops dcmipp_byteproc_video_ops = {
545 .s_stream = v4l2_subdev_s_stream_helper,
546 };
547
548 static const struct v4l2_subdev_ops dcmipp_byteproc_ops = {
549 .pad = &dcmipp_byteproc_pad_ops,
550 .video = &dcmipp_byteproc_video_ops,
551 };
552
dcmipp_byteproc_release(struct v4l2_subdev * sd)553 static void dcmipp_byteproc_release(struct v4l2_subdev *sd)
554 {
555 struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
556
557 kfree(byteproc);
558 }
559
560 static const struct v4l2_subdev_internal_ops dcmipp_byteproc_int_ops = {
561 .init_state = dcmipp_byteproc_init_state,
562 .release = dcmipp_byteproc_release,
563 };
564
dcmipp_byteproc_ent_release(struct dcmipp_ent_device * ved)565 void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved)
566 {
567 struct dcmipp_byteproc_device *byteproc =
568 container_of(ved, struct dcmipp_byteproc_device, ved);
569
570 dcmipp_ent_sd_unregister(ved, &byteproc->sd);
571 }
572
573 struct dcmipp_ent_device *
dcmipp_byteproc_ent_init(struct device * dev,const char * entity_name,struct v4l2_device * v4l2_dev,void __iomem * regs)574 dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name,
575 struct v4l2_device *v4l2_dev, void __iomem *regs)
576 {
577 struct dcmipp_byteproc_device *byteproc;
578 const unsigned long pads_flag[] = {
579 MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE,
580 };
581 int ret;
582
583 /* Allocate the byteproc struct */
584 byteproc = kzalloc_obj(*byteproc);
585 if (!byteproc)
586 return ERR_PTR(-ENOMEM);
587
588 byteproc->regs = regs;
589
590 /* Initialize ved and sd */
591 ret = dcmipp_ent_sd_register(&byteproc->ved, &byteproc->sd,
592 v4l2_dev, entity_name,
593 MEDIA_ENT_F_PROC_VIDEO_SCALER,
594 ARRAY_SIZE(pads_flag), pads_flag,
595 &dcmipp_byteproc_int_ops,
596 &dcmipp_byteproc_ops,
597 NULL, NULL);
598 if (ret) {
599 kfree(byteproc);
600 return ERR_PTR(ret);
601 }
602
603 byteproc->dev = dev;
604
605 return &byteproc->ved;
606 }
607