]> Git Repo - J-linux.git/blob - drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / media / platform / raspberrypi / rp1-cfe / pisp-fe.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * PiSP Front End Driver
4  *
5  * Copyright (c) 2021-2024 Raspberry Pi Ltd.
6  */
7
8 #include <linux/bitops.h>
9 #include <linux/delay.h>
10 #include <linux/moduleparam.h>
11 #include <linux/pm_runtime.h>
12 #include <linux/seq_file.h>
13
14 #include <media/videobuf2-dma-contig.h>
15
16 #include "cfe.h"
17 #include "pisp-fe.h"
18
19 #include "cfe-trace.h"
20
21 #define FE_VERSION              0x000
22 #define FE_CONTROL              0x004
23 #define FE_STATUS               0x008
24 #define FE_FRAME_STATUS         0x00c
25 #define FE_ERROR_STATUS         0x010
26 #define FE_OUTPUT_STATUS        0x014
27 #define FE_INT_EN               0x018
28 #define FE_INT_STATUS           0x01c
29
30 /* CONTROL */
31 #define FE_CONTROL_QUEUE        BIT(0)
32 #define FE_CONTROL_ABORT        BIT(1)
33 #define FE_CONTROL_RESET        BIT(2)
34 #define FE_CONTROL_LATCH_REGS   BIT(3)
35
36 /* INT_EN / INT_STATUS */
37 #define FE_INT_EOF              BIT(0)
38 #define FE_INT_SOF              BIT(1)
39 #define FE_INT_LINES0           BIT(8)
40 #define FE_INT_LINES1           BIT(9)
41 #define FE_INT_STATS            BIT(16)
42 #define FE_INT_QREADY           BIT(24)
43
44 /* STATUS */
45 #define FE_STATUS_QUEUED        BIT(0)
46 #define FE_STATUS_WAITING       BIT(1)
47 #define FE_STATUS_ACTIVE        BIT(2)
48
49 #define PISP_FE_CONFIG_BASE_OFFSET      0x0040
50
51 #define PISP_FE_ENABLE_STATS_CLUSTER \
52         (PISP_FE_ENABLE_STATS_CROP | PISP_FE_ENABLE_DECIMATE    | \
53          PISP_FE_ENABLE_BLC        | PISP_FE_ENABLE_CDAF_STATS  | \
54          PISP_FE_ENABLE_AWB_STATS  | PISP_FE_ENABLE_RGBY        | \
55          PISP_FE_ENABLE_LSC        | PISP_FE_ENABLE_AGC_STATS)
56
57 #define PISP_FE_ENABLE_OUTPUT_CLUSTER(i)                                \
58         ((PISP_FE_ENABLE_CROP0     | PISP_FE_ENABLE_DOWNSCALE0 |        \
59           PISP_FE_ENABLE_COMPRESS0 | PISP_FE_ENABLE_OUTPUT0) << (4 * (i)))
60
61 struct pisp_fe_config_param {
62         u32 dirty_flags;
63         u32 dirty_flags_extra;
64         size_t offset;
65         size_t size;
66 };
67
68 static const struct pisp_fe_config_param pisp_fe_config_map[] = {
69         /* *_dirty_flag_extra types */
70         { 0, PISP_FE_DIRTY_GLOBAL,
71                 offsetof(struct pisp_fe_config, global),
72                 sizeof(struct pisp_fe_global_config) },
73         { 0, PISP_FE_DIRTY_FLOATING,
74                 offsetof(struct pisp_fe_config, floating_stats),
75                 sizeof(struct pisp_fe_floating_stats_config) },
76         { 0, PISP_FE_DIRTY_OUTPUT_AXI,
77                 offsetof(struct pisp_fe_config, output_axi),
78                 sizeof(struct pisp_fe_output_axi_config) },
79         /* *_dirty_flag types */
80         { PISP_FE_ENABLE_INPUT, 0,
81                 offsetof(struct pisp_fe_config, input),
82                 sizeof(struct pisp_fe_input_config) },
83         { PISP_FE_ENABLE_DECOMPRESS, 0,
84                 offsetof(struct pisp_fe_config, decompress),
85                 sizeof(struct pisp_decompress_config) },
86         { PISP_FE_ENABLE_DECOMPAND, 0,
87                 offsetof(struct pisp_fe_config, decompand),
88                 sizeof(struct pisp_fe_decompand_config) },
89         { PISP_FE_ENABLE_BLA, 0,
90                 offsetof(struct pisp_fe_config, bla),
91                 sizeof(struct pisp_bla_config) },
92         { PISP_FE_ENABLE_DPC, 0,
93                 offsetof(struct pisp_fe_config, dpc),
94                 sizeof(struct pisp_fe_dpc_config) },
95         { PISP_FE_ENABLE_STATS_CROP, 0,
96                 offsetof(struct pisp_fe_config, stats_crop),
97                 sizeof(struct pisp_fe_crop_config) },
98         { PISP_FE_ENABLE_BLC, 0,
99                 offsetof(struct pisp_fe_config, blc),
100                 sizeof(struct pisp_bla_config) },
101         { PISP_FE_ENABLE_CDAF_STATS, 0,
102                 offsetof(struct pisp_fe_config, cdaf_stats),
103                 sizeof(struct pisp_fe_cdaf_stats_config) },
104         { PISP_FE_ENABLE_AWB_STATS, 0,
105                 offsetof(struct pisp_fe_config, awb_stats),
106                 sizeof(struct pisp_fe_awb_stats_config) },
107         { PISP_FE_ENABLE_RGBY, 0,
108                 offsetof(struct pisp_fe_config, rgby),
109                 sizeof(struct pisp_fe_rgby_config) },
110         { PISP_FE_ENABLE_LSC, 0,
111                 offsetof(struct pisp_fe_config, lsc),
112                 sizeof(struct pisp_fe_lsc_config) },
113         { PISP_FE_ENABLE_AGC_STATS, 0,
114                 offsetof(struct pisp_fe_config, agc_stats),
115                 sizeof(struct pisp_agc_statistics) },
116         { PISP_FE_ENABLE_CROP0, 0,
117                 offsetof(struct pisp_fe_config, ch[0].crop),
118                 sizeof(struct pisp_fe_crop_config) },
119         { PISP_FE_ENABLE_DOWNSCALE0, 0,
120                 offsetof(struct pisp_fe_config, ch[0].downscale),
121                 sizeof(struct pisp_fe_downscale_config) },
122         { PISP_FE_ENABLE_COMPRESS0, 0,
123                 offsetof(struct pisp_fe_config, ch[0].compress),
124                 sizeof(struct pisp_compress_config) },
125         { PISP_FE_ENABLE_OUTPUT0, 0,
126                 offsetof(struct pisp_fe_config, ch[0].output),
127                 sizeof(struct pisp_fe_output_config) },
128         { PISP_FE_ENABLE_CROP1, 0,
129                 offsetof(struct pisp_fe_config, ch[1].crop),
130                 sizeof(struct pisp_fe_crop_config) },
131         { PISP_FE_ENABLE_DOWNSCALE1, 0,
132                 offsetof(struct pisp_fe_config, ch[1].downscale),
133                 sizeof(struct pisp_fe_downscale_config) },
134         { PISP_FE_ENABLE_COMPRESS1, 0,
135                 offsetof(struct pisp_fe_config, ch[1].compress),
136                 sizeof(struct pisp_compress_config) },
137         { PISP_FE_ENABLE_OUTPUT1, 0,
138                 offsetof(struct pisp_fe_config, ch[1].output),
139                 sizeof(struct pisp_fe_output_config) },
140 };
141
142 #define pisp_fe_dbg(fe, fmt, arg...) dev_dbg((fe)->v4l2_dev->dev, fmt, ##arg)
143 #define pisp_fe_info(fe, fmt, arg...) dev_info((fe)->v4l2_dev->dev, fmt, ##arg)
144 #define pisp_fe_err(fe, fmt, arg...) dev_err((fe)->v4l2_dev->dev, fmt, ##arg)
145
146 static inline u32 pisp_fe_reg_read(struct pisp_fe_device *fe, u32 offset)
147 {
148         return readl(fe->base + offset);
149 }
150
151 static inline void pisp_fe_reg_write(struct pisp_fe_device *fe, u32 offset,
152                                      u32 val)
153 {
154         writel(val, fe->base + offset);
155 }
156
157 static inline void pisp_fe_reg_write_relaxed(struct pisp_fe_device *fe,
158                                              u32 offset, u32 val)
159 {
160         writel_relaxed(val, fe->base + offset);
161 }
162
163 static int pisp_fe_regs_show(struct seq_file *s, void *data)
164 {
165         struct pisp_fe_device *fe = s->private;
166         int ret;
167
168         ret = pm_runtime_resume_and_get(fe->v4l2_dev->dev);
169         if (ret)
170                 return ret;
171
172         pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS);
173
174 #define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", pisp_fe_reg_read(fe, reg))
175         DUMP(FE_VERSION);
176         DUMP(FE_CONTROL);
177         DUMP(FE_STATUS);
178         DUMP(FE_FRAME_STATUS);
179         DUMP(FE_ERROR_STATUS);
180         DUMP(FE_OUTPUT_STATUS);
181         DUMP(FE_INT_EN);
182         DUMP(FE_INT_STATUS);
183 #undef DUMP
184
185         pm_runtime_put(fe->v4l2_dev->dev);
186
187         return 0;
188 }
189
190 DEFINE_SHOW_ATTRIBUTE(pisp_fe_regs);
191
192 static void pisp_fe_config_write(struct pisp_fe_device *fe,
193                                  struct pisp_fe_config *config,
194                                  unsigned int start_offset, unsigned int size)
195 {
196         const unsigned int max_offset =
197                 offsetof(struct pisp_fe_config, ch[PISP_FE_NUM_OUTPUTS]);
198         unsigned int end_offset;
199         u32 *cfg = (u32 *)config;
200
201         start_offset = min(start_offset, max_offset);
202         end_offset = min(start_offset + size, max_offset);
203
204         cfg += start_offset >> 2;
205         for (unsigned int i = start_offset; i < end_offset; i += 4, cfg++)
206                 pisp_fe_reg_write_relaxed(fe, PISP_FE_CONFIG_BASE_OFFSET + i,
207                                           *cfg);
208 }
209
210 void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof)
211 {
212         u32 status, int_status, out_status, frame_status, error_status;
213
214         pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS);
215         status = pisp_fe_reg_read(fe, FE_STATUS);
216         out_status = pisp_fe_reg_read(fe, FE_OUTPUT_STATUS);
217         frame_status = pisp_fe_reg_read(fe, FE_FRAME_STATUS);
218         error_status = pisp_fe_reg_read(fe, FE_ERROR_STATUS);
219
220         int_status = pisp_fe_reg_read(fe, FE_INT_STATUS);
221         pisp_fe_reg_write(fe, FE_INT_STATUS, int_status);
222
223         trace_fe_irq(status, out_status, frame_status, error_status,
224                      int_status);
225
226         /* We do not report interrupts for the input/stream pad. */
227         for (unsigned int i = 0; i < FE_NUM_PADS - 1; i++) {
228                 sof[i] = !!(int_status & FE_INT_SOF);
229                 eof[i] = !!(int_status & FE_INT_EOF);
230         }
231 }
232
233 static bool pisp_fe_validate_output(struct pisp_fe_config const *cfg,
234                                     unsigned int c, struct v4l2_format const *f)
235 {
236         unsigned int wbytes;
237
238         wbytes = cfg->ch[c].output.format.width;
239         if (cfg->ch[c].output.format.format & PISP_IMAGE_FORMAT_BPS_MASK)
240                 wbytes *= 2;
241
242         /* Check output image dimensions are nonzero and not too big */
243         if (cfg->ch[c].output.format.width < 2 ||
244             cfg->ch[c].output.format.height < 2 ||
245             cfg->ch[c].output.format.height > f->fmt.pix.height ||
246             cfg->ch[c].output.format.stride > f->fmt.pix.bytesperline ||
247             wbytes > f->fmt.pix.bytesperline)
248                 return false;
249
250         /* Check for zero-sized crops, which could cause lockup */
251         if ((cfg->global.enables & PISP_FE_ENABLE_CROP(c)) &&
252             ((cfg->ch[c].crop.offset_x >= (cfg->input.format.width & ~1) ||
253               cfg->ch[c].crop.offset_y >= cfg->input.format.height ||
254               cfg->ch[c].crop.width < 2 || cfg->ch[c].crop.height < 2)))
255                 return false;
256
257         if ((cfg->global.enables & PISP_FE_ENABLE_DOWNSCALE(c)) &&
258             (cfg->ch[c].downscale.output_width < 2 ||
259              cfg->ch[c].downscale.output_height < 2))
260                 return false;
261
262         return true;
263 }
264
265 static bool pisp_fe_validate_stats(struct pisp_fe_config const *cfg)
266 {
267         /* Check for zero-sized crop, which could cause lockup */
268         return (!(cfg->global.enables & PISP_FE_ENABLE_STATS_CROP) ||
269                 (cfg->stats_crop.offset_x < (cfg->input.format.width & ~1) &&
270                  cfg->stats_crop.offset_y < cfg->input.format.height &&
271                  cfg->stats_crop.width >= 2 && cfg->stats_crop.height >= 2));
272 }
273
274 int pisp_fe_validate_config(struct pisp_fe_device *fe,
275                             struct pisp_fe_config *cfg,
276                             struct v4l2_format const *f0,
277                             struct v4l2_format const *f1)
278 {
279         /*
280          * Check the input is enabled, streaming and has nonzero size;
281          * to avoid cases where the hardware might lock up or try to
282          * read inputs from memory (which this driver doesn't support).
283          */
284         if (!(cfg->global.enables & PISP_FE_ENABLE_INPUT) ||
285             cfg->input.streaming != 1 || cfg->input.format.width < 2 ||
286             cfg->input.format.height < 2) {
287                 pisp_fe_err(fe, "%s: Input config not valid", __func__);
288                 return -EINVAL;
289         }
290
291         for (unsigned int i = 0; i < PISP_FE_NUM_OUTPUTS; i++) {
292                 if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i))) {
293                         if (cfg->global.enables &
294                                         PISP_FE_ENABLE_OUTPUT_CLUSTER(i)) {
295                                 pisp_fe_err(fe, "%s: Output %u not valid",
296                                             __func__, i);
297                                 return -EINVAL;
298                         }
299                         continue;
300                 }
301
302                 if (!pisp_fe_validate_output(cfg, i, i ? f1 : f0))
303                         return -EINVAL;
304         }
305
306         if ((cfg->global.enables & PISP_FE_ENABLE_STATS_CLUSTER) &&
307             !pisp_fe_validate_stats(cfg)) {
308                 pisp_fe_err(fe, "%s: Stats config not valid", __func__);
309                 return -EINVAL;
310         }
311
312         return 0;
313 }
314
315 void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs,
316                         struct pisp_fe_config *cfg)
317 {
318         u64 addr;
319         u32 status;
320
321         /*
322          * Check output buffers exist and outputs are correctly configured.
323          * If valid, set the buffer's DMA address; otherwise disable.
324          */
325         for (unsigned int i = 0; i < PISP_FE_NUM_OUTPUTS; i++) {
326                 struct vb2_buffer *buf = vb2_bufs[FE_OUTPUT0_PAD + i];
327
328                 if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i)))
329                         continue;
330
331                 addr = vb2_dma_contig_plane_dma_addr(buf, 0);
332                 cfg->output_buffer[i].addr_lo = addr & 0xffffffff;
333                 cfg->output_buffer[i].addr_hi = addr >> 32;
334         }
335
336         if (vb2_bufs[FE_STATS_PAD]) {
337                 addr = vb2_dma_contig_plane_dma_addr(vb2_bufs[FE_STATS_PAD], 0);
338                 cfg->stats_buffer.addr_lo = addr & 0xffffffff;
339                 cfg->stats_buffer.addr_hi = addr >> 32;
340         }
341
342         /* Set up ILINES interrupts 3/4 of the way down each output */
343         cfg->ch[0].output.ilines =
344                 max(0x80u, (3u * cfg->ch[0].output.format.height) >> 2);
345         cfg->ch[1].output.ilines =
346                 max(0x80u, (3u * cfg->ch[1].output.format.height) >> 2);
347
348         /*
349          * The hardware must have consumed the previous config by now.
350          * This read of status also serves as a memory barrier before the
351          * sequence of relaxed writes which follow.
352          */
353         status = pisp_fe_reg_read(fe, FE_STATUS);
354         if (WARN_ON(status & FE_STATUS_QUEUED))
355                 return;
356
357         /*
358          * Unconditionally write buffers, global and input parameters.
359          * Write cropping and output parameters whenever they are enabled.
360          * Selectively write other parameters that have been marked as
361          * changed through the dirty flags.
362          */
363         pisp_fe_config_write(fe, cfg, 0,
364                              offsetof(struct pisp_fe_config, decompress));
365         cfg->dirty_flags_extra &= ~PISP_FE_DIRTY_GLOBAL;
366         cfg->dirty_flags &= ~PISP_FE_ENABLE_INPUT;
367         cfg->dirty_flags |= (cfg->global.enables &
368                              (PISP_FE_ENABLE_STATS_CROP        |
369                               PISP_FE_ENABLE_OUTPUT_CLUSTER(0) |
370                               PISP_FE_ENABLE_OUTPUT_CLUSTER(1)));
371         for (unsigned int i = 0; i < ARRAY_SIZE(pisp_fe_config_map); i++) {
372                 const struct pisp_fe_config_param *p = &pisp_fe_config_map[i];
373
374                 if (cfg->dirty_flags & p->dirty_flags ||
375                     cfg->dirty_flags_extra & p->dirty_flags_extra)
376                         pisp_fe_config_write(fe, cfg, p->offset, p->size);
377         }
378
379         /* This final non-relaxed write serves as a memory barrier */
380         pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_QUEUE);
381 }
382
383 void pisp_fe_start(struct pisp_fe_device *fe)
384 {
385         pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_RESET);
386         pisp_fe_reg_write(fe, FE_INT_STATUS, ~0);
387         pisp_fe_reg_write(fe, FE_INT_EN, FE_INT_EOF | FE_INT_SOF |
388                                          FE_INT_LINES0 | FE_INT_LINES1);
389         fe->inframe_count = 0;
390 }
391
392 void pisp_fe_stop(struct pisp_fe_device *fe)
393 {
394         pisp_fe_reg_write(fe, FE_INT_EN, 0);
395         pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_ABORT);
396         usleep_range(1000, 2000);
397         WARN_ON(pisp_fe_reg_read(fe, FE_STATUS));
398         pisp_fe_reg_write(fe, FE_INT_STATUS, ~0);
399 }
400
401 static int pisp_fe_init_state(struct v4l2_subdev *sd,
402                               struct v4l2_subdev_state *state)
403 {
404         struct v4l2_mbus_framefmt *fmt;
405
406         fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD);
407         *fmt = cfe_default_format;
408         fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16;
409
410         fmt = v4l2_subdev_state_get_format(state, FE_CONFIG_PAD);
411         fmt->code = MEDIA_BUS_FMT_FIXED;
412         fmt->width = sizeof(struct pisp_fe_config);
413         fmt->height = 1;
414
415         fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT0_PAD);
416         *fmt = cfe_default_format;
417         fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16;
418
419         fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT1_PAD);
420         *fmt = cfe_default_format;
421         fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16;
422
423         fmt = v4l2_subdev_state_get_format(state, FE_STATS_PAD);
424         fmt->code = MEDIA_BUS_FMT_FIXED;
425         fmt->width = sizeof(struct pisp_statistics);
426         fmt->height = 1;
427
428         return 0;
429 }
430
431 static int pisp_fe_pad_set_fmt(struct v4l2_subdev *sd,
432                                struct v4l2_subdev_state *state,
433                                struct v4l2_subdev_format *format)
434 {
435         struct v4l2_mbus_framefmt *fmt;
436         const struct cfe_fmt *cfe_fmt;
437
438         /* TODO: format propagation to source pads */
439         /* TODO: format validation */
440
441         switch (format->pad) {
442         case FE_STREAM_PAD:
443                 cfe_fmt = find_format_by_code(format->format.code);
444                 if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT))
445                         cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16);
446
447                 format->format.code = cfe_fmt->code;
448                 format->format.field = V4L2_FIELD_NONE;
449
450                 fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD);
451                 *fmt = format->format;
452
453                 fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT0_PAD);
454                 *fmt = format->format;
455
456                 fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT1_PAD);
457                 *fmt = format->format;
458
459                 return 0;
460
461         case FE_OUTPUT0_PAD:
462         case FE_OUTPUT1_PAD: {
463                 /*
464                  * TODO: we should allow scaling and cropping by allowing the
465                  * user to set the size here.
466                  */
467                 struct v4l2_mbus_framefmt *sink_fmt, *source_fmt;
468                 u32 sink_code;
469                 u32 code;
470
471                 cfe_fmt = find_format_by_code(format->format.code);
472                 if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT))
473                         cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16);
474
475                 format->format.code = cfe_fmt->code;
476
477                 sink_fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD);
478                 if (!sink_fmt)
479                         return -EINVAL;
480
481                 source_fmt = v4l2_subdev_state_get_format(state, format->pad);
482                 if (!source_fmt)
483                         return -EINVAL;
484
485                 sink_code = sink_fmt->code;
486                 code = format->format.code;
487
488                 /*
489                  * If the source code from the user does not match the code in
490                  * the sink pad, check that the source code matches the
491                  * compressed version of the sink code.
492                  */
493
494                 if (code != sink_code &&
495                     code == cfe_find_compressed_code(sink_code))
496                         source_fmt->code = code;
497
498                 return 0;
499         }
500
501         case FE_CONFIG_PAD:
502         case FE_STATS_PAD:
503         default:
504                 return v4l2_subdev_get_fmt(sd, state, format);
505         }
506 }
507
508 static const struct v4l2_subdev_pad_ops pisp_fe_subdev_pad_ops = {
509         .get_fmt = v4l2_subdev_get_fmt,
510         .set_fmt = pisp_fe_pad_set_fmt,
511         .link_validate = v4l2_subdev_link_validate_default,
512 };
513
514 static int pisp_fe_link_validate(struct media_link *link)
515 {
516         struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(link->sink->entity);
517         struct pisp_fe_device *fe = container_of(sd, struct pisp_fe_device, sd);
518
519         pisp_fe_dbg(fe, "%s: link \"%s\":%u -> \"%s\":%u\n", __func__,
520                     link->source->entity->name, link->source->index,
521                     link->sink->entity->name, link->sink->index);
522
523         if (link->sink->index == FE_STREAM_PAD)
524                 return v4l2_subdev_link_validate(link);
525
526         if (link->sink->index == FE_CONFIG_PAD)
527                 return 0;
528
529         return -EINVAL;
530 }
531
532 static const struct media_entity_operations pisp_fe_entity_ops = {
533         .link_validate = pisp_fe_link_validate,
534 };
535
536 static const struct v4l2_subdev_ops pisp_fe_subdev_ops = {
537         .pad = &pisp_fe_subdev_pad_ops,
538 };
539
540 static const struct v4l2_subdev_internal_ops pisp_fe_internal_ops = {
541         .init_state = pisp_fe_init_state,
542 };
543
544 int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs)
545 {
546         int ret;
547
548         debugfs_create_file("fe_regs", 0440, debugfs, fe, &pisp_fe_regs_fops);
549
550         fe->hw_revision = pisp_fe_reg_read(fe, FE_VERSION);
551         pisp_fe_info(fe, "PiSP FE HW v%u.%u\n",
552                      (fe->hw_revision >> 24) & 0xff,
553                      (fe->hw_revision >> 20) & 0x0f);
554
555         fe->pad[FE_STREAM_PAD].flags =
556                 MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
557         fe->pad[FE_CONFIG_PAD].flags = MEDIA_PAD_FL_SINK;
558         fe->pad[FE_OUTPUT0_PAD].flags = MEDIA_PAD_FL_SOURCE;
559         fe->pad[FE_OUTPUT1_PAD].flags = MEDIA_PAD_FL_SOURCE;
560         fe->pad[FE_STATS_PAD].flags = MEDIA_PAD_FL_SOURCE;
561
562         ret = media_entity_pads_init(&fe->sd.entity, ARRAY_SIZE(fe->pad),
563                                      fe->pad);
564         if (ret)
565                 return ret;
566
567         /* Initialize subdev */
568         v4l2_subdev_init(&fe->sd, &pisp_fe_subdev_ops);
569         fe->sd.internal_ops = &pisp_fe_internal_ops;
570         fe->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
571         fe->sd.entity.ops = &pisp_fe_entity_ops;
572         fe->sd.entity.name = "pisp-fe";
573         fe->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
574         fe->sd.owner = THIS_MODULE;
575         snprintf(fe->sd.name, sizeof(fe->sd.name), "pisp-fe");
576
577         ret = v4l2_subdev_init_finalize(&fe->sd);
578         if (ret)
579                 goto err_entity_cleanup;
580
581         ret = v4l2_device_register_subdev(fe->v4l2_dev, &fe->sd);
582         if (ret) {
583                 pisp_fe_err(fe, "Failed register pisp fe subdev (%d)\n", ret);
584                 goto err_subdev_cleanup;
585         }
586
587         /* Must be in IDLE state (STATUS == 0) here. */
588         WARN_ON(pisp_fe_reg_read(fe, FE_STATUS));
589
590         return 0;
591
592 err_subdev_cleanup:
593         v4l2_subdev_cleanup(&fe->sd);
594 err_entity_cleanup:
595         media_entity_cleanup(&fe->sd.entity);
596
597         return ret;
598 }
599
600 void pisp_fe_uninit(struct pisp_fe_device *fe)
601 {
602         v4l2_device_unregister_subdev(&fe->sd);
603         v4l2_subdev_cleanup(&fe->sd);
604         media_entity_cleanup(&fe->sd.entity);
605 }
This page took 0.060411 seconds and 4 git commands to generate.