.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * TI VPFE capture Driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
5 | 6 | * |
---|
6 | 7 | * Benoit Parrot <bparrot@ti.com> |
---|
7 | 8 | * Lad, Prabhakar <prabhakar.csengg@gmail.com> |
---|
8 | | - * |
---|
9 | | - * This program is free software; you may redistribute it and/or modify |
---|
10 | | - * it under the terms of the GNU General Public License as published by |
---|
11 | | - * the Free Software Foundation; version 2 of the License. |
---|
12 | | - * |
---|
13 | | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
---|
14 | | - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
---|
15 | | - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
---|
16 | | - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
---|
17 | | - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
---|
18 | | - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
---|
19 | | - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
---|
20 | | - * SOFTWARE. |
---|
21 | 9 | */ |
---|
22 | 10 | |
---|
23 | 11 | #include <linux/delay.h> |
---|
.. | .. |
---|
38 | 26 | #include <media/v4l2-ctrls.h> |
---|
39 | 27 | #include <media/v4l2-event.h> |
---|
40 | 28 | #include <media/v4l2-fwnode.h> |
---|
| 29 | +#include <media/v4l2-rect.h> |
---|
41 | 30 | |
---|
42 | 31 | #include "am437x-vpfe.h" |
---|
43 | 32 | |
---|
.. | .. |
---|
69 | 58 | {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, |
---|
70 | 59 | }; |
---|
71 | 60 | |
---|
72 | | -struct bus_format { |
---|
73 | | - unsigned int width; |
---|
74 | | - unsigned int bpp; |
---|
75 | | -}; |
---|
76 | | - |
---|
77 | | -/* |
---|
78 | | - * struct vpfe_fmt - VPFE media bus format information |
---|
79 | | - * @name: V4L2 format description |
---|
80 | | - * @code: V4L2 media bus format code |
---|
81 | | - * @shifted: V4L2 media bus format code for the same pixel layout but |
---|
82 | | - * shifted to be 8 bits per pixel. =0 if format is not shiftable. |
---|
83 | | - * @pixelformat: V4L2 pixel format FCC identifier |
---|
84 | | - * @width: Bits per pixel (when transferred over a bus) |
---|
85 | | - * @bpp: Bytes per pixel (when stored in memory) |
---|
86 | | - * @supported: Indicates format supported by subdev |
---|
87 | | - */ |
---|
88 | | -struct vpfe_fmt { |
---|
89 | | - const char *name; |
---|
90 | | - u32 fourcc; |
---|
91 | | - u32 code; |
---|
92 | | - struct bus_format l; |
---|
93 | | - struct bus_format s; |
---|
94 | | - bool supported; |
---|
95 | | - u32 index; |
---|
96 | | -}; |
---|
97 | | - |
---|
98 | | -static struct vpfe_fmt formats[] = { |
---|
| 61 | +static struct vpfe_fmt formats[VPFE_NUM_FORMATS] = { |
---|
99 | 62 | { |
---|
100 | | - .name = "YUV 4:2:2 packed, YCbYCr", |
---|
101 | 63 | .fourcc = V4L2_PIX_FMT_YUYV, |
---|
102 | 64 | .code = MEDIA_BUS_FMT_YUYV8_2X8, |
---|
103 | | - .l.width = 10, |
---|
104 | | - .l.bpp = 4, |
---|
105 | | - .s.width = 8, |
---|
106 | | - .s.bpp = 2, |
---|
107 | | - .supported = false, |
---|
| 65 | + .bitsperpixel = 16, |
---|
108 | 66 | }, { |
---|
109 | | - .name = "YUV 4:2:2 packed, CbYCrY", |
---|
110 | 67 | .fourcc = V4L2_PIX_FMT_UYVY, |
---|
111 | 68 | .code = MEDIA_BUS_FMT_UYVY8_2X8, |
---|
112 | | - .l.width = 10, |
---|
113 | | - .l.bpp = 4, |
---|
114 | | - .s.width = 8, |
---|
115 | | - .s.bpp = 2, |
---|
116 | | - .supported = false, |
---|
| 69 | + .bitsperpixel = 16, |
---|
117 | 70 | }, { |
---|
118 | | - .name = "YUV 4:2:2 packed, YCrYCb", |
---|
119 | 71 | .fourcc = V4L2_PIX_FMT_YVYU, |
---|
120 | 72 | .code = MEDIA_BUS_FMT_YVYU8_2X8, |
---|
121 | | - .l.width = 10, |
---|
122 | | - .l.bpp = 4, |
---|
123 | | - .s.width = 8, |
---|
124 | | - .s.bpp = 2, |
---|
125 | | - .supported = false, |
---|
| 73 | + .bitsperpixel = 16, |
---|
126 | 74 | }, { |
---|
127 | | - .name = "YUV 4:2:2 packed, CrYCbY", |
---|
128 | 75 | .fourcc = V4L2_PIX_FMT_VYUY, |
---|
129 | 76 | .code = MEDIA_BUS_FMT_VYUY8_2X8, |
---|
130 | | - .l.width = 10, |
---|
131 | | - .l.bpp = 4, |
---|
132 | | - .s.width = 8, |
---|
133 | | - .s.bpp = 2, |
---|
134 | | - .supported = false, |
---|
| 77 | + .bitsperpixel = 16, |
---|
135 | 78 | }, { |
---|
136 | | - .name = "RAW8 BGGR", |
---|
137 | 79 | .fourcc = V4L2_PIX_FMT_SBGGR8, |
---|
138 | 80 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, |
---|
139 | | - .l.width = 10, |
---|
140 | | - .l.bpp = 2, |
---|
141 | | - .s.width = 8, |
---|
142 | | - .s.bpp = 1, |
---|
143 | | - .supported = false, |
---|
| 81 | + .bitsperpixel = 8, |
---|
144 | 82 | }, { |
---|
145 | | - .name = "RAW8 GBRG", |
---|
146 | 83 | .fourcc = V4L2_PIX_FMT_SGBRG8, |
---|
147 | 84 | .code = MEDIA_BUS_FMT_SGBRG8_1X8, |
---|
148 | | - .l.width = 10, |
---|
149 | | - .l.bpp = 2, |
---|
150 | | - .s.width = 8, |
---|
151 | | - .s.bpp = 1, |
---|
152 | | - .supported = false, |
---|
| 85 | + .bitsperpixel = 8, |
---|
153 | 86 | }, { |
---|
154 | | - .name = "RAW8 GRBG", |
---|
155 | 87 | .fourcc = V4L2_PIX_FMT_SGRBG8, |
---|
156 | 88 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, |
---|
157 | | - .l.width = 10, |
---|
158 | | - .l.bpp = 2, |
---|
159 | | - .s.width = 8, |
---|
160 | | - .s.bpp = 1, |
---|
161 | | - .supported = false, |
---|
| 89 | + .bitsperpixel = 8, |
---|
162 | 90 | }, { |
---|
163 | | - .name = "RAW8 RGGB", |
---|
164 | 91 | .fourcc = V4L2_PIX_FMT_SRGGB8, |
---|
165 | 92 | .code = MEDIA_BUS_FMT_SRGGB8_1X8, |
---|
166 | | - .l.width = 10, |
---|
167 | | - .l.bpp = 2, |
---|
168 | | - .s.width = 8, |
---|
169 | | - .s.bpp = 1, |
---|
170 | | - .supported = false, |
---|
| 93 | + .bitsperpixel = 8, |
---|
171 | 94 | }, { |
---|
172 | | - .name = "RGB565 (LE)", |
---|
173 | 95 | .fourcc = V4L2_PIX_FMT_RGB565, |
---|
174 | 96 | .code = MEDIA_BUS_FMT_RGB565_2X8_LE, |
---|
175 | | - .l.width = 10, |
---|
176 | | - .l.bpp = 4, |
---|
177 | | - .s.width = 8, |
---|
178 | | - .s.bpp = 2, |
---|
179 | | - .supported = false, |
---|
| 97 | + .bitsperpixel = 16, |
---|
180 | 98 | }, { |
---|
181 | | - .name = "RGB565 (BE)", |
---|
182 | 99 | .fourcc = V4L2_PIX_FMT_RGB565X, |
---|
183 | 100 | .code = MEDIA_BUS_FMT_RGB565_2X8_BE, |
---|
184 | | - .l.width = 10, |
---|
185 | | - .l.bpp = 4, |
---|
186 | | - .s.width = 8, |
---|
187 | | - .s.bpp = 2, |
---|
188 | | - .supported = false, |
---|
| 101 | + .bitsperpixel = 16, |
---|
189 | 102 | }, |
---|
190 | 103 | }; |
---|
191 | 104 | |
---|
192 | | -static int |
---|
193 | | -__vpfe_get_format(struct vpfe_device *vpfe, |
---|
194 | | - struct v4l2_format *format, unsigned int *bpp); |
---|
| 105 | +static int __subdev_get_format(struct vpfe_device *vpfe, |
---|
| 106 | + struct v4l2_mbus_framefmt *fmt); |
---|
| 107 | +static int vpfe_calc_format_size(struct vpfe_device *vpfe, |
---|
| 108 | + const struct vpfe_fmt *fmt, |
---|
| 109 | + struct v4l2_format *f); |
---|
195 | 110 | |
---|
196 | | -static struct vpfe_fmt *find_format_by_code(unsigned int code) |
---|
| 111 | +static struct vpfe_fmt *find_format_by_code(struct vpfe_device *vpfe, |
---|
| 112 | + unsigned int code) |
---|
197 | 113 | { |
---|
198 | 114 | struct vpfe_fmt *fmt; |
---|
199 | 115 | unsigned int k; |
---|
200 | 116 | |
---|
201 | | - for (k = 0; k < ARRAY_SIZE(formats); k++) { |
---|
202 | | - fmt = &formats[k]; |
---|
| 117 | + for (k = 0; k < vpfe->num_active_fmt; k++) { |
---|
| 118 | + fmt = vpfe->active_fmt[k]; |
---|
203 | 119 | if (fmt->code == code) |
---|
204 | 120 | return fmt; |
---|
205 | 121 | } |
---|
.. | .. |
---|
207 | 123 | return NULL; |
---|
208 | 124 | } |
---|
209 | 125 | |
---|
210 | | -static struct vpfe_fmt *find_format_by_pix(unsigned int pixelformat) |
---|
| 126 | +static struct vpfe_fmt *find_format_by_pix(struct vpfe_device *vpfe, |
---|
| 127 | + unsigned int pixelformat) |
---|
211 | 128 | { |
---|
212 | 129 | struct vpfe_fmt *fmt; |
---|
213 | 130 | unsigned int k; |
---|
214 | 131 | |
---|
215 | | - for (k = 0; k < ARRAY_SIZE(formats); k++) { |
---|
216 | | - fmt = &formats[k]; |
---|
| 132 | + for (k = 0; k < vpfe->num_active_fmt; k++) { |
---|
| 133 | + fmt = vpfe->active_fmt[k]; |
---|
217 | 134 | if (fmt->fourcc == pixelformat) |
---|
218 | 135 | return fmt; |
---|
219 | 136 | } |
---|
.. | .. |
---|
221 | 138 | return NULL; |
---|
222 | 139 | } |
---|
223 | 140 | |
---|
224 | | -static void |
---|
225 | | -mbus_to_pix(struct vpfe_device *vpfe, |
---|
226 | | - const struct v4l2_mbus_framefmt *mbus, |
---|
227 | | - struct v4l2_pix_format *pix, unsigned int *bpp) |
---|
| 141 | +static unsigned int __get_bytesperpixel(struct vpfe_device *vpfe, |
---|
| 142 | + const struct vpfe_fmt *fmt) |
---|
228 | 143 | { |
---|
229 | 144 | struct vpfe_subdev_info *sdinfo = vpfe->current_subdev; |
---|
230 | 145 | unsigned int bus_width = sdinfo->vpfe_param.bus_width; |
---|
231 | | - struct vpfe_fmt *fmt; |
---|
| 146 | + u32 bpp, bus_width_bytes, clocksperpixel; |
---|
232 | 147 | |
---|
233 | | - fmt = find_format_by_code(mbus->code); |
---|
234 | | - if (WARN_ON(fmt == NULL)) { |
---|
235 | | - pr_err("Invalid mbus code set\n"); |
---|
236 | | - *bpp = 1; |
---|
237 | | - return; |
---|
238 | | - } |
---|
| 148 | + bus_width_bytes = ALIGN(bus_width, 8) >> 3; |
---|
| 149 | + clocksperpixel = DIV_ROUND_UP(fmt->bitsperpixel, bus_width); |
---|
| 150 | + bpp = clocksperpixel * bus_width_bytes; |
---|
239 | 151 | |
---|
240 | | - memset(pix, 0, sizeof(*pix)); |
---|
241 | | - v4l2_fill_pix_format(pix, mbus); |
---|
242 | | - pix->pixelformat = fmt->fourcc; |
---|
243 | | - *bpp = (bus_width == 10) ? fmt->l.bpp : fmt->s.bpp; |
---|
244 | | - |
---|
245 | | - /* pitch should be 32 bytes aligned */ |
---|
246 | | - pix->bytesperline = ALIGN(pix->width * *bpp, 32); |
---|
247 | | - pix->sizeimage = pix->bytesperline * pix->height; |
---|
248 | | -} |
---|
249 | | - |
---|
250 | | -static void pix_to_mbus(struct vpfe_device *vpfe, |
---|
251 | | - struct v4l2_pix_format *pix_fmt, |
---|
252 | | - struct v4l2_mbus_framefmt *mbus_fmt) |
---|
253 | | -{ |
---|
254 | | - struct vpfe_fmt *fmt; |
---|
255 | | - |
---|
256 | | - fmt = find_format_by_pix(pix_fmt->pixelformat); |
---|
257 | | - if (!fmt) { |
---|
258 | | - /* default to first entry */ |
---|
259 | | - vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", |
---|
260 | | - pix_fmt->pixelformat); |
---|
261 | | - fmt = &formats[0]; |
---|
262 | | - } |
---|
263 | | - |
---|
264 | | - memset(mbus_fmt, 0, sizeof(*mbus_fmt)); |
---|
265 | | - v4l2_fill_mbus_format(mbus_fmt, pix_fmt, fmt->code); |
---|
| 152 | + return bpp; |
---|
266 | 153 | } |
---|
267 | 154 | |
---|
268 | 155 | /* Print Four-character-code (FOURCC) */ |
---|
.. | .. |
---|
277 | 164 | code[4] = '\0'; |
---|
278 | 165 | |
---|
279 | 166 | return code; |
---|
280 | | -} |
---|
281 | | - |
---|
282 | | -static int |
---|
283 | | -cmp_v4l2_format(const struct v4l2_format *lhs, const struct v4l2_format *rhs) |
---|
284 | | -{ |
---|
285 | | - return lhs->type == rhs->type && |
---|
286 | | - lhs->fmt.pix.width == rhs->fmt.pix.width && |
---|
287 | | - lhs->fmt.pix.height == rhs->fmt.pix.height && |
---|
288 | | - lhs->fmt.pix.pixelformat == rhs->fmt.pix.pixelformat && |
---|
289 | | - lhs->fmt.pix.field == rhs->fmt.pix.field && |
---|
290 | | - lhs->fmt.pix.colorspace == rhs->fmt.pix.colorspace && |
---|
291 | | - lhs->fmt.pix.ycbcr_enc == rhs->fmt.pix.ycbcr_enc && |
---|
292 | | - lhs->fmt.pix.quantization == rhs->fmt.pix.quantization && |
---|
293 | | - lhs->fmt.pix.xfer_func == rhs->fmt.pix.xfer_func; |
---|
294 | 167 | } |
---|
295 | 168 | |
---|
296 | 169 | static inline u32 vpfe_reg_read(struct vpfe_ccdc *ccdc, u32 offset) |
---|
.. | .. |
---|
357 | 230 | if (frm_fmt == CCDC_FRMFMT_INTERLACED) { |
---|
358 | 231 | vert_nr_lines = (image_win->height >> 1) - 1; |
---|
359 | 232 | vert_start >>= 1; |
---|
360 | | - /* Since first line doesn't have any data */ |
---|
361 | | - vert_start += 1; |
---|
362 | 233 | /* configure VDINT0 */ |
---|
363 | 234 | val = (vert_start << VPFE_VDINT_VDINT0_SHIFT); |
---|
364 | 235 | } else { |
---|
365 | | - /* Since first line doesn't have any data */ |
---|
366 | | - vert_start += 1; |
---|
367 | 236 | vert_nr_lines = image_win->height - 1; |
---|
368 | 237 | /* |
---|
369 | 238 | * configure VDINT0 and VDINT1. VDINT1 will be at half |
---|
.. | .. |
---|
417 | 286 | max_data = ccdc_data_size_max_bit(ccdcparam->data_sz); |
---|
418 | 287 | |
---|
419 | 288 | if (ccdcparam->alaw.gamma_wd > VPFE_CCDC_GAMMA_BITS_09_0 || |
---|
420 | | - ccdcparam->alaw.gamma_wd < VPFE_CCDC_GAMMA_BITS_15_6 || |
---|
| 289 | + ccdcparam->data_sz > VPFE_CCDC_DATA_8BITS || |
---|
421 | 290 | max_gamma > max_data) { |
---|
422 | 291 | vpfe_dbg(1, vpfe, "Invalid data line select\n"); |
---|
423 | 292 | return -EINVAL; |
---|
.. | .. |
---|
457 | 326 | |
---|
458 | 327 | static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev) |
---|
459 | 328 | { |
---|
460 | | - int dma_cntl, i, pcr; |
---|
| 329 | + struct vpfe_device *vpfe = to_vpfe(ccdc); |
---|
| 330 | + u32 dma_cntl, pcr; |
---|
461 | 331 | |
---|
462 | | - /* If the CCDC module is still busy wait for it to be done */ |
---|
463 | | - for (i = 0; i < 10; i++) { |
---|
464 | | - usleep_range(5000, 6000); |
---|
465 | | - pcr = vpfe_reg_read(ccdc, VPFE_PCR); |
---|
466 | | - if (!pcr) |
---|
467 | | - break; |
---|
| 332 | + pcr = vpfe_reg_read(ccdc, VPFE_PCR); |
---|
| 333 | + if (pcr) |
---|
| 334 | + vpfe_dbg(1, vpfe, "VPFE_PCR is still set (%x)", pcr); |
---|
468 | 335 | |
---|
469 | | - /* make sure it it is disabled */ |
---|
470 | | - vpfe_pcr_enable(ccdc, 0); |
---|
471 | | - } |
---|
| 336 | + dma_cntl = vpfe_reg_read(ccdc, VPFE_DMA_CNTL); |
---|
| 337 | + if ((dma_cntl & VPFE_DMA_CNTL_OVERFLOW)) |
---|
| 338 | + vpfe_dbg(1, vpfe, "VPFE_DMA_CNTL_OVERFLOW is still set (%x)", |
---|
| 339 | + dma_cntl); |
---|
472 | 340 | |
---|
473 | 341 | /* Disable CCDC by resetting all register to default POR values */ |
---|
474 | 342 | vpfe_ccdc_restore_defaults(ccdc); |
---|
475 | | - |
---|
476 | | - /* if DMA_CNTL overflow bit is set. Clear it |
---|
477 | | - * It appears to take a while for this to become quiescent ~20ms |
---|
478 | | - */ |
---|
479 | | - for (i = 0; i < 10; i++) { |
---|
480 | | - dma_cntl = vpfe_reg_read(ccdc, VPFE_DMA_CNTL); |
---|
481 | | - if (!(dma_cntl & VPFE_DMA_CNTL_OVERFLOW)) |
---|
482 | | - break; |
---|
483 | | - |
---|
484 | | - /* Clear the overflow bit */ |
---|
485 | | - vpfe_reg_write(ccdc, dma_cntl, VPFE_DMA_CNTL); |
---|
486 | | - usleep_range(5000, 6000); |
---|
487 | | - } |
---|
488 | 343 | |
---|
489 | 344 | /* Disabled the module at the CONFIG level */ |
---|
490 | 345 | vpfe_config_enable(ccdc, 0); |
---|
491 | 346 | |
---|
492 | 347 | pm_runtime_put_sync(dev); |
---|
493 | | - |
---|
494 | 348 | return 0; |
---|
495 | 349 | } |
---|
496 | 350 | |
---|
497 | 351 | static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params) |
---|
498 | 352 | { |
---|
499 | | - struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); |
---|
| 353 | + struct vpfe_device *vpfe = to_vpfe(ccdc); |
---|
500 | 354 | struct vpfe_ccdc_config_params_raw raw_params; |
---|
501 | 355 | int x; |
---|
502 | 356 | |
---|
.. | .. |
---|
506 | 360 | x = copy_from_user(&raw_params, params, sizeof(raw_params)); |
---|
507 | 361 | if (x) { |
---|
508 | 362 | vpfe_dbg(1, vpfe, |
---|
509 | | - "vpfe_ccdc_set_params: error in copying ccdc params, %d\n", |
---|
510 | | - x); |
---|
| 363 | + "%s: error in copying ccdc params, %d\n", |
---|
| 364 | + __func__, x); |
---|
511 | 365 | return -EFAULT; |
---|
512 | 366 | } |
---|
513 | 367 | |
---|
.. | .. |
---|
525 | 379 | */ |
---|
526 | 380 | static void vpfe_ccdc_config_ycbcr(struct vpfe_ccdc *ccdc) |
---|
527 | 381 | { |
---|
528 | | - struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); |
---|
529 | 382 | struct ccdc_params_ycbcr *params = &ccdc->ccdc_cfg.ycbcr; |
---|
530 | 383 | u32 syn_mode; |
---|
531 | 384 | |
---|
532 | | - vpfe_dbg(3, vpfe, "vpfe_ccdc_config_ycbcr:\n"); |
---|
533 | 385 | /* |
---|
534 | 386 | * first restore the CCDC registers to default values |
---|
535 | 387 | * This is important since we assume default values to be set in |
---|
.. | .. |
---|
654 | 506 | */ |
---|
655 | 507 | static void vpfe_ccdc_config_raw(struct vpfe_ccdc *ccdc) |
---|
656 | 508 | { |
---|
657 | | - struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); |
---|
| 509 | + struct vpfe_device *vpfe = to_vpfe(ccdc); |
---|
658 | 510 | struct vpfe_ccdc_config_params_raw *config_params = |
---|
659 | 511 | &ccdc->ccdc_cfg.bayer.config_params; |
---|
660 | 512 | struct ccdc_params_raw *params = &ccdc->ccdc_cfg.bayer; |
---|
661 | 513 | unsigned int syn_mode; |
---|
662 | 514 | unsigned int val; |
---|
663 | | - |
---|
664 | | - vpfe_dbg(3, vpfe, "vpfe_ccdc_config_raw:\n"); |
---|
665 | 515 | |
---|
666 | 516 | /* Reset CCDC */ |
---|
667 | 517 | vpfe_ccdc_restore_defaults(ccdc); |
---|
.. | .. |
---|
761 | 611 | |
---|
762 | 612 | static int vpfe_ccdc_set_pixel_format(struct vpfe_ccdc *ccdc, u32 pixfmt) |
---|
763 | 613 | { |
---|
764 | | - struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); |
---|
| 614 | + struct vpfe_device *vpfe = to_vpfe(ccdc); |
---|
765 | 615 | |
---|
766 | | - vpfe_dbg(1, vpfe, "vpfe_ccdc_set_pixel_format: if_type: %d, pixfmt:%s\n", |
---|
767 | | - ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt)); |
---|
| 616 | + vpfe_dbg(1, vpfe, "%s: if_type: %d, pixfmt:%s\n", |
---|
| 617 | + __func__, ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt)); |
---|
768 | 618 | |
---|
769 | 619 | if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { |
---|
770 | 620 | ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; |
---|
.. | .. |
---|
893 | 743 | static int vpfe_ccdc_set_hw_if_params(struct vpfe_ccdc *ccdc, |
---|
894 | 744 | struct vpfe_hw_if_param *params) |
---|
895 | 745 | { |
---|
896 | | - struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); |
---|
| 746 | + struct vpfe_device *vpfe = to_vpfe(ccdc); |
---|
897 | 747 | |
---|
898 | 748 | ccdc->ccdc_cfg.if_type = params->if_type; |
---|
899 | 749 | |
---|
.. | .. |
---|
1048 | 898 | static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) |
---|
1049 | 899 | { |
---|
1050 | 900 | enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; |
---|
| 901 | + u32 bpp; |
---|
1051 | 902 | int ret = 0; |
---|
1052 | | - |
---|
1053 | | - vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n"); |
---|
1054 | 903 | |
---|
1055 | 904 | vpfe_dbg(1, vpfe, "pixelformat: %s\n", |
---|
1056 | 905 | print_fourcc(vpfe->fmt.fmt.pix.pixelformat)); |
---|
.. | .. |
---|
1062 | 911 | } |
---|
1063 | 912 | |
---|
1064 | 913 | /* configure the image window */ |
---|
1065 | | - vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, vpfe->bpp); |
---|
| 914 | + bpp = __get_bytesperpixel(vpfe, vpfe->current_vpfe_fmt); |
---|
| 915 | + vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, bpp); |
---|
1066 | 916 | |
---|
1067 | 917 | switch (vpfe->fmt.fmt.pix.field) { |
---|
1068 | 918 | case V4L2_FIELD_INTERLACED: |
---|
.. | .. |
---|
1106 | 956 | static int vpfe_config_image_format(struct vpfe_device *vpfe, |
---|
1107 | 957 | v4l2_std_id std_id) |
---|
1108 | 958 | { |
---|
1109 | | - struct v4l2_pix_format *pix = &vpfe->fmt.fmt.pix; |
---|
| 959 | + struct vpfe_fmt *fmt; |
---|
| 960 | + struct v4l2_mbus_framefmt mbus_fmt; |
---|
1110 | 961 | int i, ret; |
---|
1111 | 962 | |
---|
1112 | 963 | for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { |
---|
.. | .. |
---|
1128 | 979 | return -EINVAL; |
---|
1129 | 980 | } |
---|
1130 | 981 | |
---|
1131 | | - vpfe->crop.top = vpfe->crop.left = 0; |
---|
1132 | | - vpfe->crop.width = vpfe->std_info.active_pixels; |
---|
1133 | | - vpfe->crop.height = vpfe->std_info.active_lines; |
---|
1134 | | - pix->width = vpfe->crop.width; |
---|
1135 | | - pix->height = vpfe->crop.height; |
---|
1136 | | - pix->pixelformat = V4L2_PIX_FMT_YUYV; |
---|
1137 | | - |
---|
1138 | | - /* first field and frame format based on standard frame format */ |
---|
1139 | | - if (vpfe->std_info.frame_format) |
---|
1140 | | - pix->field = V4L2_FIELD_INTERLACED; |
---|
1141 | | - else |
---|
1142 | | - pix->field = V4L2_FIELD_NONE; |
---|
1143 | | - |
---|
1144 | | - ret = __vpfe_get_format(vpfe, &vpfe->fmt, &vpfe->bpp); |
---|
| 982 | + ret = __subdev_get_format(vpfe, &mbus_fmt); |
---|
1145 | 983 | if (ret) |
---|
1146 | 984 | return ret; |
---|
1147 | 985 | |
---|
| 986 | + fmt = find_format_by_code(vpfe, mbus_fmt.code); |
---|
| 987 | + if (!fmt) { |
---|
| 988 | + vpfe_dbg(3, vpfe, "mbus code format (0x%08x) not found.\n", |
---|
| 989 | + mbus_fmt.code); |
---|
| 990 | + return -EINVAL; |
---|
| 991 | + } |
---|
| 992 | + |
---|
| 993 | + /* Save current subdev format */ |
---|
| 994 | + v4l2_fill_pix_format(&vpfe->fmt.fmt.pix, &mbus_fmt); |
---|
| 995 | + vpfe->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
---|
| 996 | + vpfe->fmt.fmt.pix.pixelformat = fmt->fourcc; |
---|
| 997 | + vpfe_calc_format_size(vpfe, fmt, &vpfe->fmt); |
---|
| 998 | + vpfe->current_vpfe_fmt = fmt; |
---|
| 999 | + |
---|
1148 | 1000 | /* Update the crop window based on found values */ |
---|
1149 | | - vpfe->crop.width = pix->width; |
---|
1150 | | - vpfe->crop.height = pix->height; |
---|
| 1001 | + vpfe->crop.top = 0; |
---|
| 1002 | + vpfe->crop.left = 0; |
---|
| 1003 | + vpfe->crop.width = mbus_fmt.width; |
---|
| 1004 | + vpfe->crop.height = mbus_fmt.height; |
---|
1151 | 1005 | |
---|
1152 | 1006 | return vpfe_config_ccdc_image_format(vpfe); |
---|
1153 | 1007 | } |
---|
.. | .. |
---|
1167 | 1021 | if (ret) |
---|
1168 | 1022 | return ret; |
---|
1169 | 1023 | |
---|
1170 | | - pm_runtime_get_sync(vpfe->pdev); |
---|
| 1024 | + ret = pm_runtime_resume_and_get(vpfe->pdev); |
---|
| 1025 | + if (ret < 0) |
---|
| 1026 | + return ret; |
---|
1171 | 1027 | |
---|
1172 | 1028 | vpfe_config_enable(&vpfe->ccdc, 1); |
---|
1173 | 1029 | |
---|
.. | .. |
---|
1249 | 1105 | * This function will get next buffer from the dma queue and |
---|
1250 | 1106 | * set the buffer address in the vpfe register for capture. |
---|
1251 | 1107 | * the buffer is marked active |
---|
1252 | | - * |
---|
1253 | | - * Assumes caller is holding vpfe->dma_queue_lock already |
---|
1254 | 1108 | */ |
---|
1255 | | -static inline void vpfe_schedule_next_buffer(struct vpfe_device *vpfe) |
---|
| 1109 | +static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe) |
---|
1256 | 1110 | { |
---|
| 1111 | + dma_addr_t addr; |
---|
| 1112 | + |
---|
| 1113 | + spin_lock(&vpfe->dma_queue_lock); |
---|
| 1114 | + if (list_empty(&vpfe->dma_queue)) { |
---|
| 1115 | + spin_unlock(&vpfe->dma_queue_lock); |
---|
| 1116 | + return; |
---|
| 1117 | + } |
---|
| 1118 | + |
---|
1257 | 1119 | vpfe->next_frm = list_entry(vpfe->dma_queue.next, |
---|
1258 | 1120 | struct vpfe_cap_buffer, list); |
---|
1259 | 1121 | list_del(&vpfe->next_frm->list); |
---|
| 1122 | + spin_unlock(&vpfe->dma_queue_lock); |
---|
1260 | 1123 | |
---|
1261 | | - vpfe_set_sdr_addr(&vpfe->ccdc, |
---|
1262 | | - vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb.vb2_buf, 0)); |
---|
| 1124 | + addr = vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb.vb2_buf, 0); |
---|
| 1125 | + vpfe_set_sdr_addr(&vpfe->ccdc, addr); |
---|
1263 | 1126 | } |
---|
1264 | 1127 | |
---|
1265 | 1128 | static inline void vpfe_schedule_bottom_field(struct vpfe_device *vpfe) |
---|
1266 | 1129 | { |
---|
1267 | | - unsigned long addr; |
---|
| 1130 | + dma_addr_t addr; |
---|
1268 | 1131 | |
---|
1269 | 1132 | addr = vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb.vb2_buf, 0) + |
---|
1270 | 1133 | vpfe->field_off; |
---|
.. | .. |
---|
1289 | 1152 | vpfe->cur_frm = vpfe->next_frm; |
---|
1290 | 1153 | } |
---|
1291 | 1154 | |
---|
| 1155 | +static void vpfe_handle_interlaced_irq(struct vpfe_device *vpfe, |
---|
| 1156 | + enum v4l2_field field) |
---|
| 1157 | +{ |
---|
| 1158 | + int fid; |
---|
| 1159 | + |
---|
| 1160 | + /* interlaced or TB capture check which field |
---|
| 1161 | + * we are in hardware |
---|
| 1162 | + */ |
---|
| 1163 | + fid = vpfe_ccdc_getfid(&vpfe->ccdc); |
---|
| 1164 | + |
---|
| 1165 | + /* switch the software maintained field id */ |
---|
| 1166 | + vpfe->field ^= 1; |
---|
| 1167 | + if (fid == vpfe->field) { |
---|
| 1168 | + /* we are in-sync here,continue */ |
---|
| 1169 | + if (fid == 0) { |
---|
| 1170 | + /* |
---|
| 1171 | + * One frame is just being captured. If the |
---|
| 1172 | + * next frame is available, release the |
---|
| 1173 | + * current frame and move on |
---|
| 1174 | + */ |
---|
| 1175 | + if (vpfe->cur_frm != vpfe->next_frm) |
---|
| 1176 | + vpfe_process_buffer_complete(vpfe); |
---|
| 1177 | + |
---|
| 1178 | + if (vpfe->stopping) |
---|
| 1179 | + return; |
---|
| 1180 | + |
---|
| 1181 | + /* |
---|
| 1182 | + * based on whether the two fields are stored |
---|
| 1183 | + * interleave or separately in memory, |
---|
| 1184 | + * reconfigure the CCDC memory address |
---|
| 1185 | + */ |
---|
| 1186 | + if (field == V4L2_FIELD_SEQ_TB) |
---|
| 1187 | + vpfe_schedule_bottom_field(vpfe); |
---|
| 1188 | + } else { |
---|
| 1189 | + /* |
---|
| 1190 | + * if one field is just being captured configure |
---|
| 1191 | + * the next frame get the next frame from the empty |
---|
| 1192 | + * queue if no frame is available hold on to the |
---|
| 1193 | + * current buffer |
---|
| 1194 | + */ |
---|
| 1195 | + if (vpfe->cur_frm == vpfe->next_frm) |
---|
| 1196 | + vpfe_schedule_next_buffer(vpfe); |
---|
| 1197 | + } |
---|
| 1198 | + } else if (fid == 0) { |
---|
| 1199 | + /* |
---|
| 1200 | + * out of sync. Recover from any hardware out-of-sync. |
---|
| 1201 | + * May loose one frame |
---|
| 1202 | + */ |
---|
| 1203 | + vpfe->field = fid; |
---|
| 1204 | + } |
---|
| 1205 | +} |
---|
| 1206 | + |
---|
1292 | 1207 | /* |
---|
1293 | 1208 | * vpfe_isr : ISR handler for vpfe capture (VINT0) |
---|
1294 | 1209 | * @irq: irq number |
---|
.. | .. |
---|
1300 | 1215 | static irqreturn_t vpfe_isr(int irq, void *dev) |
---|
1301 | 1216 | { |
---|
1302 | 1217 | struct vpfe_device *vpfe = (struct vpfe_device *)dev; |
---|
1303 | | - enum v4l2_field field; |
---|
1304 | | - int intr_status; |
---|
1305 | | - int fid; |
---|
| 1218 | + enum v4l2_field field = vpfe->fmt.fmt.pix.field; |
---|
| 1219 | + int intr_status, stopping = vpfe->stopping; |
---|
1306 | 1220 | |
---|
1307 | 1221 | intr_status = vpfe_reg_read(&vpfe->ccdc, VPFE_IRQ_STS); |
---|
1308 | 1222 | |
---|
1309 | 1223 | if (intr_status & VPFE_VDINT0) { |
---|
1310 | | - field = vpfe->fmt.fmt.pix.field; |
---|
1311 | | - |
---|
1312 | 1224 | if (field == V4L2_FIELD_NONE) { |
---|
1313 | | - /* handle progressive frame capture */ |
---|
1314 | 1225 | if (vpfe->cur_frm != vpfe->next_frm) |
---|
1315 | 1226 | vpfe_process_buffer_complete(vpfe); |
---|
1316 | | - goto next_intr; |
---|
| 1227 | + } else { |
---|
| 1228 | + vpfe_handle_interlaced_irq(vpfe, field); |
---|
1317 | 1229 | } |
---|
1318 | | - |
---|
1319 | | - /* interlaced or TB capture check which field |
---|
1320 | | - we are in hardware */ |
---|
1321 | | - fid = vpfe_ccdc_getfid(&vpfe->ccdc); |
---|
1322 | | - |
---|
1323 | | - /* switch the software maintained field id */ |
---|
1324 | | - vpfe->field ^= 1; |
---|
1325 | | - if (fid == vpfe->field) { |
---|
1326 | | - /* we are in-sync here,continue */ |
---|
1327 | | - if (fid == 0) { |
---|
1328 | | - /* |
---|
1329 | | - * One frame is just being captured. If the |
---|
1330 | | - * next frame is available, release the |
---|
1331 | | - * current frame and move on |
---|
1332 | | - */ |
---|
1333 | | - if (vpfe->cur_frm != vpfe->next_frm) |
---|
1334 | | - vpfe_process_buffer_complete(vpfe); |
---|
1335 | | - /* |
---|
1336 | | - * based on whether the two fields are stored |
---|
1337 | | - * interleave or separately in memory, |
---|
1338 | | - * reconfigure the CCDC memory address |
---|
1339 | | - */ |
---|
1340 | | - if (field == V4L2_FIELD_SEQ_TB) |
---|
1341 | | - vpfe_schedule_bottom_field(vpfe); |
---|
1342 | | - |
---|
1343 | | - goto next_intr; |
---|
1344 | | - } |
---|
1345 | | - /* |
---|
1346 | | - * if one field is just being captured configure |
---|
1347 | | - * the next frame get the next frame from the empty |
---|
1348 | | - * queue if no frame is available hold on to the |
---|
1349 | | - * current buffer |
---|
1350 | | - */ |
---|
1351 | | - spin_lock(&vpfe->dma_queue_lock); |
---|
1352 | | - if (!list_empty(&vpfe->dma_queue) && |
---|
1353 | | - vpfe->cur_frm == vpfe->next_frm) |
---|
1354 | | - vpfe_schedule_next_buffer(vpfe); |
---|
1355 | | - spin_unlock(&vpfe->dma_queue_lock); |
---|
1356 | | - } else if (fid == 0) { |
---|
1357 | | - /* |
---|
1358 | | - * out of sync. Recover from any hardware out-of-sync. |
---|
1359 | | - * May loose one frame |
---|
1360 | | - */ |
---|
1361 | | - vpfe->field = fid; |
---|
| 1230 | + if (stopping) { |
---|
| 1231 | + vpfe->stopping = false; |
---|
| 1232 | + complete(&vpfe->capture_stop); |
---|
1362 | 1233 | } |
---|
1363 | 1234 | } |
---|
1364 | 1235 | |
---|
1365 | | -next_intr: |
---|
1366 | | - if (intr_status & VPFE_VDINT1) { |
---|
1367 | | - spin_lock(&vpfe->dma_queue_lock); |
---|
1368 | | - if (vpfe->fmt.fmt.pix.field == V4L2_FIELD_NONE && |
---|
1369 | | - !list_empty(&vpfe->dma_queue) && |
---|
| 1236 | + if (intr_status & VPFE_VDINT1 && !stopping) { |
---|
| 1237 | + if (field == V4L2_FIELD_NONE && |
---|
1370 | 1238 | vpfe->cur_frm == vpfe->next_frm) |
---|
1371 | 1239 | vpfe_schedule_next_buffer(vpfe); |
---|
1372 | | - spin_unlock(&vpfe->dma_queue_lock); |
---|
1373 | 1240 | } |
---|
1374 | 1241 | |
---|
1375 | 1242 | vpfe_clear_intr(&vpfe->ccdc, intr_status); |
---|
.. | .. |
---|
1406 | 1273 | { |
---|
1407 | 1274 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1408 | 1275 | |
---|
1409 | | - vpfe_dbg(2, vpfe, "vpfe_querycap\n"); |
---|
1410 | | - |
---|
1411 | | - strlcpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver)); |
---|
1412 | | - strlcpy(cap->card, "TI AM437x VPFE", sizeof(cap->card)); |
---|
| 1276 | + strscpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver)); |
---|
| 1277 | + strscpy(cap->card, "TI AM437x VPFE", sizeof(cap->card)); |
---|
1413 | 1278 | snprintf(cap->bus_info, sizeof(cap->bus_info), |
---|
1414 | 1279 | "platform:%s", vpfe->v4l2_dev.name); |
---|
1415 | | - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | |
---|
1416 | | - V4L2_CAP_READWRITE; |
---|
1417 | | - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; |
---|
1418 | | - |
---|
1419 | 1280 | return 0; |
---|
1420 | 1281 | } |
---|
1421 | 1282 | |
---|
1422 | 1283 | /* get the format set at output pad of the adjacent subdev */ |
---|
1423 | | -static int __vpfe_get_format(struct vpfe_device *vpfe, |
---|
1424 | | - struct v4l2_format *format, unsigned int *bpp) |
---|
| 1284 | +static int __subdev_get_format(struct vpfe_device *vpfe, |
---|
| 1285 | + struct v4l2_mbus_framefmt *fmt) |
---|
1425 | 1286 | { |
---|
1426 | | - struct v4l2_mbus_framefmt mbus_fmt; |
---|
1427 | | - struct vpfe_subdev_info *sdinfo; |
---|
1428 | | - struct v4l2_subdev_format fmt; |
---|
| 1287 | + struct v4l2_subdev *sd = vpfe->current_subdev->sd; |
---|
| 1288 | + struct v4l2_subdev_format sd_fmt; |
---|
| 1289 | + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; |
---|
1429 | 1290 | int ret; |
---|
1430 | 1291 | |
---|
1431 | | - sdinfo = vpfe->current_subdev; |
---|
1432 | | - if (!sdinfo->sd) |
---|
1433 | | - return -EINVAL; |
---|
| 1292 | + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
---|
| 1293 | + sd_fmt.pad = 0; |
---|
1434 | 1294 | |
---|
1435 | | - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
---|
1436 | | - fmt.pad = 0; |
---|
1437 | | - |
---|
1438 | | - ret = v4l2_subdev_call(sdinfo->sd, pad, get_fmt, NULL, &fmt); |
---|
1439 | | - if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) |
---|
| 1295 | + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); |
---|
| 1296 | + if (ret) |
---|
1440 | 1297 | return ret; |
---|
1441 | 1298 | |
---|
1442 | | - if (!ret) { |
---|
1443 | | - v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); |
---|
1444 | | - mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); |
---|
1445 | | - } else { |
---|
1446 | | - ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, |
---|
1447 | | - sdinfo->grp_id, |
---|
1448 | | - pad, get_fmt, |
---|
1449 | | - NULL, &fmt); |
---|
1450 | | - if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) |
---|
1451 | | - return ret; |
---|
1452 | | - v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); |
---|
1453 | | - mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp); |
---|
1454 | | - } |
---|
| 1299 | + *fmt = *mbus_fmt; |
---|
1455 | 1300 | |
---|
1456 | | - format->type = vpfe->fmt.type; |
---|
1457 | | - |
---|
1458 | | - vpfe_dbg(1, vpfe, |
---|
1459 | | - "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n", |
---|
1460 | | - __func__, format->fmt.pix.width, format->fmt.pix.height, |
---|
1461 | | - print_fourcc(format->fmt.pix.pixelformat), |
---|
1462 | | - format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp); |
---|
| 1301 | + vpfe_dbg(1, vpfe, "%s: %dx%d code:%04X\n", __func__, |
---|
| 1302 | + fmt->width, fmt->height, fmt->code); |
---|
1463 | 1303 | |
---|
1464 | 1304 | return 0; |
---|
1465 | 1305 | } |
---|
1466 | 1306 | |
---|
1467 | 1307 | /* set the format at output pad of the adjacent subdev */ |
---|
1468 | | -static int __vpfe_set_format(struct vpfe_device *vpfe, |
---|
1469 | | - struct v4l2_format *format, unsigned int *bpp) |
---|
| 1308 | +static int __subdev_set_format(struct vpfe_device *vpfe, |
---|
| 1309 | + struct v4l2_mbus_framefmt *fmt) |
---|
1470 | 1310 | { |
---|
1471 | | - struct vpfe_subdev_info *sdinfo; |
---|
1472 | | - struct v4l2_subdev_format fmt; |
---|
| 1311 | + struct v4l2_subdev *sd = vpfe->current_subdev->sd; |
---|
| 1312 | + struct v4l2_subdev_format sd_fmt; |
---|
| 1313 | + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; |
---|
1473 | 1314 | int ret; |
---|
1474 | 1315 | |
---|
1475 | | - vpfe_dbg(2, vpfe, "__vpfe_set_format\n"); |
---|
| 1316 | + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
---|
| 1317 | + sd_fmt.pad = 0; |
---|
| 1318 | + *mbus_fmt = *fmt; |
---|
1476 | 1319 | |
---|
1477 | | - sdinfo = vpfe->current_subdev; |
---|
1478 | | - if (!sdinfo->sd) |
---|
1479 | | - return -EINVAL; |
---|
1480 | | - |
---|
1481 | | - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
---|
1482 | | - fmt.pad = 0; |
---|
1483 | | - |
---|
1484 | | - pix_to_mbus(vpfe, &format->fmt.pix, &fmt.format); |
---|
1485 | | - |
---|
1486 | | - ret = v4l2_subdev_call(sdinfo->sd, pad, set_fmt, NULL, &fmt); |
---|
| 1320 | + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sd_fmt); |
---|
1487 | 1321 | if (ret) |
---|
1488 | 1322 | return ret; |
---|
1489 | 1323 | |
---|
1490 | | - v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); |
---|
1491 | | - mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); |
---|
| 1324 | + vpfe_dbg(1, vpfe, "%s %dx%d code:%04X\n", __func__, |
---|
| 1325 | + fmt->width, fmt->height, fmt->code); |
---|
1492 | 1326 | |
---|
1493 | | - format->type = vpfe->fmt.type; |
---|
| 1327 | + return 0; |
---|
| 1328 | +} |
---|
1494 | 1329 | |
---|
1495 | | - vpfe_dbg(1, vpfe, |
---|
1496 | | - "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n", |
---|
1497 | | - __func__, format->fmt.pix.width, format->fmt.pix.height, |
---|
1498 | | - print_fourcc(format->fmt.pix.pixelformat), |
---|
1499 | | - format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp); |
---|
| 1330 | +static int vpfe_calc_format_size(struct vpfe_device *vpfe, |
---|
| 1331 | + const struct vpfe_fmt *fmt, |
---|
| 1332 | + struct v4l2_format *f) |
---|
| 1333 | +{ |
---|
| 1334 | + u32 bpp; |
---|
| 1335 | + |
---|
| 1336 | + if (!fmt) { |
---|
| 1337 | + vpfe_dbg(3, vpfe, "No vpfe_fmt provided!\n"); |
---|
| 1338 | + return -EINVAL; |
---|
| 1339 | + } |
---|
| 1340 | + |
---|
| 1341 | + bpp = __get_bytesperpixel(vpfe, fmt); |
---|
| 1342 | + |
---|
| 1343 | + /* pitch should be 32 bytes aligned */ |
---|
| 1344 | + f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.width * bpp, 32); |
---|
| 1345 | + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * |
---|
| 1346 | + f->fmt.pix.height; |
---|
| 1347 | + |
---|
| 1348 | + vpfe_dbg(3, vpfe, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n", |
---|
| 1349 | + __func__, print_fourcc(f->fmt.pix.pixelformat), |
---|
| 1350 | + f->fmt.pix.width, f->fmt.pix.height, |
---|
| 1351 | + f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); |
---|
1500 | 1352 | |
---|
1501 | 1353 | return 0; |
---|
1502 | 1354 | } |
---|
.. | .. |
---|
1505 | 1357 | struct v4l2_format *fmt) |
---|
1506 | 1358 | { |
---|
1507 | 1359 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1508 | | - |
---|
1509 | | - vpfe_dbg(2, vpfe, "vpfe_g_fmt\n"); |
---|
1510 | 1360 | |
---|
1511 | 1361 | *fmt = vpfe->fmt; |
---|
1512 | 1362 | |
---|
.. | .. |
---|
1518 | 1368 | { |
---|
1519 | 1369 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1520 | 1370 | struct vpfe_subdev_info *sdinfo; |
---|
1521 | | - struct vpfe_fmt *fmt = NULL; |
---|
1522 | | - unsigned int k; |
---|
1523 | | - |
---|
1524 | | - vpfe_dbg(2, vpfe, "vpfe_enum_format index:%d\n", |
---|
1525 | | - f->index); |
---|
| 1371 | + struct vpfe_fmt *fmt; |
---|
1526 | 1372 | |
---|
1527 | 1373 | sdinfo = vpfe->current_subdev; |
---|
1528 | 1374 | if (!sdinfo->sd) |
---|
1529 | 1375 | return -EINVAL; |
---|
1530 | 1376 | |
---|
1531 | | - if (f->index > ARRAY_SIZE(formats)) |
---|
| 1377 | + if (f->index >= vpfe->num_active_fmt) |
---|
1532 | 1378 | return -EINVAL; |
---|
1533 | 1379 | |
---|
1534 | | - for (k = 0; k < ARRAY_SIZE(formats); k++) { |
---|
1535 | | - if (formats[k].index == f->index) { |
---|
1536 | | - fmt = &formats[k]; |
---|
1537 | | - break; |
---|
1538 | | - } |
---|
1539 | | - } |
---|
1540 | | - if (!fmt) |
---|
1541 | | - return -EINVAL; |
---|
| 1380 | + fmt = vpfe->active_fmt[f->index]; |
---|
1542 | 1381 | |
---|
1543 | | - strncpy(f->description, fmt->name, sizeof(f->description) - 1); |
---|
1544 | 1382 | f->pixelformat = fmt->fourcc; |
---|
1545 | | - f->type = vpfe->fmt.type; |
---|
1546 | 1383 | |
---|
1547 | | - vpfe_dbg(1, vpfe, "vpfe_enum_format: mbus index: %d code: %x pixelformat: %s [%s]\n", |
---|
1548 | | - f->index, fmt->code, print_fourcc(fmt->fourcc), fmt->name); |
---|
| 1384 | + vpfe_dbg(1, vpfe, "%s: mbus index: %d code: %x pixelformat: %s\n", |
---|
| 1385 | + __func__, f->index, fmt->code, print_fourcc(fmt->fourcc)); |
---|
1549 | 1386 | |
---|
1550 | 1387 | return 0; |
---|
1551 | 1388 | } |
---|
1552 | 1389 | |
---|
1553 | 1390 | static int vpfe_try_fmt(struct file *file, void *priv, |
---|
1554 | | - struct v4l2_format *fmt) |
---|
| 1391 | + struct v4l2_format *f) |
---|
1555 | 1392 | { |
---|
1556 | 1393 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1557 | | - unsigned int bpp; |
---|
| 1394 | + struct v4l2_subdev *sd = vpfe->current_subdev->sd; |
---|
| 1395 | + const struct vpfe_fmt *fmt; |
---|
| 1396 | + struct v4l2_subdev_frame_size_enum fse; |
---|
| 1397 | + int ret, found; |
---|
1558 | 1398 | |
---|
1559 | | - vpfe_dbg(2, vpfe, "vpfe_try_fmt\n"); |
---|
| 1399 | + fmt = find_format_by_pix(vpfe, f->fmt.pix.pixelformat); |
---|
| 1400 | + if (!fmt) { |
---|
| 1401 | + /* default to first entry */ |
---|
| 1402 | + vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", |
---|
| 1403 | + f->fmt.pix.pixelformat); |
---|
| 1404 | + fmt = vpfe->active_fmt[0]; |
---|
| 1405 | + f->fmt.pix.pixelformat = fmt->fourcc; |
---|
| 1406 | + } |
---|
1560 | 1407 | |
---|
1561 | | - return __vpfe_get_format(vpfe, fmt, &bpp); |
---|
| 1408 | + f->fmt.pix.field = vpfe->fmt.fmt.pix.field; |
---|
| 1409 | + |
---|
| 1410 | + /* check for/find a valid width/height */ |
---|
| 1411 | + ret = 0; |
---|
| 1412 | + found = false; |
---|
| 1413 | + fse.pad = 0; |
---|
| 1414 | + fse.code = fmt->code; |
---|
| 1415 | + fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
---|
| 1416 | + for (fse.index = 0; ; fse.index++) { |
---|
| 1417 | + ret = v4l2_subdev_call(sd, pad, enum_frame_size, |
---|
| 1418 | + NULL, &fse); |
---|
| 1419 | + if (ret) |
---|
| 1420 | + break; |
---|
| 1421 | + |
---|
| 1422 | + if (f->fmt.pix.width == fse.max_width && |
---|
| 1423 | + f->fmt.pix.height == fse.max_height) { |
---|
| 1424 | + found = true; |
---|
| 1425 | + break; |
---|
| 1426 | + } else if (f->fmt.pix.width >= fse.min_width && |
---|
| 1427 | + f->fmt.pix.width <= fse.max_width && |
---|
| 1428 | + f->fmt.pix.height >= fse.min_height && |
---|
| 1429 | + f->fmt.pix.height <= fse.max_height) { |
---|
| 1430 | + found = true; |
---|
| 1431 | + break; |
---|
| 1432 | + } |
---|
| 1433 | + } |
---|
| 1434 | + |
---|
| 1435 | + if (!found) { |
---|
| 1436 | + /* use existing values as default */ |
---|
| 1437 | + f->fmt.pix.width = vpfe->fmt.fmt.pix.width; |
---|
| 1438 | + f->fmt.pix.height = vpfe->fmt.fmt.pix.height; |
---|
| 1439 | + } |
---|
| 1440 | + |
---|
| 1441 | + /* |
---|
| 1442 | + * Use current colorspace for now, it will get |
---|
| 1443 | + * updated properly during s_fmt |
---|
| 1444 | + */ |
---|
| 1445 | + f->fmt.pix.colorspace = vpfe->fmt.fmt.pix.colorspace; |
---|
| 1446 | + return vpfe_calc_format_size(vpfe, fmt, f); |
---|
1562 | 1447 | } |
---|
1563 | 1448 | |
---|
1564 | 1449 | static int vpfe_s_fmt(struct file *file, void *priv, |
---|
1565 | 1450 | struct v4l2_format *fmt) |
---|
1566 | 1451 | { |
---|
1567 | 1452 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1568 | | - struct v4l2_format format; |
---|
1569 | | - unsigned int bpp; |
---|
| 1453 | + struct vpfe_fmt *f; |
---|
| 1454 | + struct v4l2_mbus_framefmt mbus_fmt; |
---|
1570 | 1455 | int ret; |
---|
1571 | | - |
---|
1572 | | - vpfe_dbg(2, vpfe, "vpfe_s_fmt\n"); |
---|
1573 | 1456 | |
---|
1574 | 1457 | /* If streaming is started, return error */ |
---|
1575 | 1458 | if (vb2_is_busy(&vpfe->buffer_queue)) { |
---|
.. | .. |
---|
1577 | 1460 | return -EBUSY; |
---|
1578 | 1461 | } |
---|
1579 | 1462 | |
---|
1580 | | - ret = __vpfe_get_format(vpfe, &format, &bpp); |
---|
| 1463 | + ret = vpfe_try_fmt(file, priv, fmt); |
---|
| 1464 | + if (ret < 0) |
---|
| 1465 | + return ret; |
---|
| 1466 | + |
---|
| 1467 | + f = find_format_by_pix(vpfe, fmt->fmt.pix.pixelformat); |
---|
| 1468 | + |
---|
| 1469 | + v4l2_fill_mbus_format(&mbus_fmt, &fmt->fmt.pix, f->code); |
---|
| 1470 | + |
---|
| 1471 | + ret = __subdev_set_format(vpfe, &mbus_fmt); |
---|
1581 | 1472 | if (ret) |
---|
1582 | 1473 | return ret; |
---|
1583 | 1474 | |
---|
| 1475 | + /* Just double check nothing has gone wrong */ |
---|
| 1476 | + if (mbus_fmt.code != f->code) { |
---|
| 1477 | + vpfe_dbg(3, vpfe, |
---|
| 1478 | + "%s subdev changed format on us, this should not happen\n", |
---|
| 1479 | + __func__); |
---|
| 1480 | + return -EINVAL; |
---|
| 1481 | + } |
---|
1584 | 1482 | |
---|
1585 | | - if (!cmp_v4l2_format(fmt, &format)) { |
---|
1586 | | - /* Sensor format is different from the requested format |
---|
1587 | | - * so we need to change it |
---|
1588 | | - */ |
---|
1589 | | - ret = __vpfe_set_format(vpfe, fmt, &bpp); |
---|
1590 | | - if (ret) |
---|
1591 | | - return ret; |
---|
1592 | | - } else /* Just make sure all of the fields are consistent */ |
---|
1593 | | - *fmt = format; |
---|
1594 | | - |
---|
1595 | | - /* First detach any IRQ if currently attached */ |
---|
1596 | | - vpfe_detach_irq(vpfe); |
---|
1597 | | - vpfe->fmt = *fmt; |
---|
1598 | | - vpfe->bpp = bpp; |
---|
| 1483 | + v4l2_fill_pix_format(&vpfe->fmt.fmt.pix, &mbus_fmt); |
---|
| 1484 | + vpfe->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
---|
| 1485 | + vpfe->fmt.fmt.pix.pixelformat = f->fourcc; |
---|
| 1486 | + vpfe_calc_format_size(vpfe, f, &vpfe->fmt); |
---|
| 1487 | + *fmt = vpfe->fmt; |
---|
| 1488 | + vpfe->current_vpfe_fmt = f; |
---|
1599 | 1489 | |
---|
1600 | 1490 | /* Update the crop window based on found values */ |
---|
1601 | 1491 | vpfe->crop.width = fmt->fmt.pix.width; |
---|
.. | .. |
---|
1610 | 1500 | { |
---|
1611 | 1501 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1612 | 1502 | struct v4l2_subdev_frame_size_enum fse; |
---|
1613 | | - struct vpfe_subdev_info *sdinfo; |
---|
1614 | | - struct v4l2_mbus_framefmt mbus; |
---|
1615 | | - struct v4l2_pix_format pix; |
---|
| 1503 | + struct v4l2_subdev *sd = vpfe->current_subdev->sd; |
---|
1616 | 1504 | struct vpfe_fmt *fmt; |
---|
1617 | 1505 | int ret; |
---|
1618 | 1506 | |
---|
1619 | | - vpfe_dbg(2, vpfe, "vpfe_enum_size\n"); |
---|
1620 | | - |
---|
1621 | 1507 | /* check for valid format */ |
---|
1622 | | - fmt = find_format_by_pix(fsize->pixel_format); |
---|
| 1508 | + fmt = find_format_by_pix(vpfe, fsize->pixel_format); |
---|
1623 | 1509 | if (!fmt) { |
---|
1624 | | - vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", |
---|
1625 | | - fsize->pixel_format); |
---|
| 1510 | + vpfe_dbg(3, vpfe, "Invalid pixel code: %x\n", |
---|
| 1511 | + fsize->pixel_format); |
---|
1626 | 1512 | return -EINVAL; |
---|
1627 | 1513 | } |
---|
1628 | 1514 | |
---|
1629 | 1515 | memset(fsize->reserved, 0x0, sizeof(fsize->reserved)); |
---|
1630 | 1516 | |
---|
1631 | | - sdinfo = vpfe->current_subdev; |
---|
1632 | | - if (!sdinfo->sd) |
---|
1633 | | - return -EINVAL; |
---|
1634 | | - |
---|
1635 | | - memset(&pix, 0x0, sizeof(pix)); |
---|
1636 | | - /* Construct pix from parameter and use default for the rest */ |
---|
1637 | | - pix.pixelformat = fsize->pixel_format; |
---|
1638 | | - pix.width = 640; |
---|
1639 | | - pix.height = 480; |
---|
1640 | | - pix.colorspace = V4L2_COLORSPACE_SRGB; |
---|
1641 | | - pix.field = V4L2_FIELD_NONE; |
---|
1642 | | - pix_to_mbus(vpfe, &pix, &mbus); |
---|
1643 | | - |
---|
1644 | 1517 | memset(&fse, 0x0, sizeof(fse)); |
---|
1645 | 1518 | fse.index = fsize->index; |
---|
1646 | 1519 | fse.pad = 0; |
---|
1647 | | - fse.code = mbus.code; |
---|
| 1520 | + fse.code = fmt->code; |
---|
1648 | 1521 | fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
---|
1649 | | - ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse); |
---|
| 1522 | + ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse); |
---|
1650 | 1523 | if (ret) |
---|
1651 | | - return -EINVAL; |
---|
| 1524 | + return ret; |
---|
1652 | 1525 | |
---|
1653 | | - vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", |
---|
1654 | | - fse.index, fse.code, fse.min_width, fse.max_width, |
---|
1655 | | - fse.min_height, fse.max_height); |
---|
| 1526 | + vpfe_dbg(1, vpfe, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", |
---|
| 1527 | + __func__, fse.index, fse.code, fse.min_width, fse.max_width, |
---|
| 1528 | + fse.min_height, fse.max_height); |
---|
1656 | 1529 | |
---|
1657 | 1530 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; |
---|
1658 | 1531 | fsize->discrete.width = fse.max_width; |
---|
1659 | 1532 | fsize->discrete.height = fse.max_height; |
---|
1660 | 1533 | |
---|
1661 | | - vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d pixformat: %s size: %dx%d\n", |
---|
1662 | | - fsize->index, print_fourcc(fsize->pixel_format), |
---|
1663 | | - fsize->discrete.width, fsize->discrete.height); |
---|
| 1534 | + vpfe_dbg(1, vpfe, "%s: index: %d pixformat: %s size: %dx%d\n", |
---|
| 1535 | + __func__, fsize->index, print_fourcc(fsize->pixel_format), |
---|
| 1536 | + fsize->discrete.width, fsize->discrete.height); |
---|
1664 | 1537 | |
---|
1665 | 1538 | return 0; |
---|
1666 | 1539 | } |
---|
.. | .. |
---|
1725 | 1598 | struct vpfe_subdev_info *sdinfo; |
---|
1726 | 1599 | int subdev, index; |
---|
1727 | 1600 | |
---|
1728 | | - vpfe_dbg(2, vpfe, "vpfe_enum_input\n"); |
---|
1729 | | - |
---|
1730 | 1601 | if (vpfe_get_subdev_input_index(vpfe, &subdev, &index, |
---|
1731 | 1602 | inp->index) < 0) { |
---|
1732 | 1603 | vpfe_dbg(1, vpfe, |
---|
.. | .. |
---|
1743 | 1614 | { |
---|
1744 | 1615 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1745 | 1616 | |
---|
1746 | | - vpfe_dbg(2, vpfe, "vpfe_g_input\n"); |
---|
1747 | | - |
---|
1748 | 1617 | return vpfe_get_app_input_index(vpfe, index); |
---|
1749 | 1618 | } |
---|
1750 | 1619 | |
---|
.. | .. |
---|
1756 | 1625 | struct vpfe_route *route; |
---|
1757 | 1626 | u32 input, output; |
---|
1758 | 1627 | int ret; |
---|
1759 | | - |
---|
1760 | | - vpfe_dbg(2, vpfe, "vpfe_set_input: index: %d\n", index); |
---|
1761 | 1628 | |
---|
1762 | 1629 | /* If streaming is started, return error */ |
---|
1763 | 1630 | if (vb2_is_busy(&vpfe->buffer_queue)) { |
---|
.. | .. |
---|
1814 | 1681 | { |
---|
1815 | 1682 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1816 | 1683 | |
---|
1817 | | - vpfe_dbg(2, vpfe, |
---|
1818 | | - "vpfe_s_input: index: %d\n", index); |
---|
1819 | | - |
---|
1820 | 1684 | return vpfe_set_input(vpfe, index); |
---|
1821 | 1685 | } |
---|
1822 | 1686 | |
---|
.. | .. |
---|
1824 | 1688 | { |
---|
1825 | 1689 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1826 | 1690 | struct vpfe_subdev_info *sdinfo; |
---|
1827 | | - |
---|
1828 | | - vpfe_dbg(2, vpfe, "vpfe_querystd\n"); |
---|
1829 | 1691 | |
---|
1830 | 1692 | sdinfo = vpfe->current_subdev; |
---|
1831 | 1693 | if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD)) |
---|
.. | .. |
---|
1841 | 1703 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1842 | 1704 | struct vpfe_subdev_info *sdinfo; |
---|
1843 | 1705 | int ret; |
---|
1844 | | - |
---|
1845 | | - vpfe_dbg(2, vpfe, "vpfe_s_std\n"); |
---|
1846 | 1706 | |
---|
1847 | 1707 | sdinfo = vpfe->current_subdev; |
---|
1848 | 1708 | if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD)) |
---|
.. | .. |
---|
1875 | 1735 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
1876 | 1736 | struct vpfe_subdev_info *sdinfo; |
---|
1877 | 1737 | |
---|
1878 | | - vpfe_dbg(2, vpfe, "vpfe_g_std\n"); |
---|
1879 | | - |
---|
1880 | 1738 | sdinfo = vpfe->current_subdev; |
---|
1881 | 1739 | if (sdinfo->inputs[0].capabilities != V4L2_IN_CAP_STD) |
---|
1882 | 1740 | return -ENODATA; |
---|
.. | .. |
---|
1893 | 1751 | static void vpfe_calculate_offsets(struct vpfe_device *vpfe) |
---|
1894 | 1752 | { |
---|
1895 | 1753 | struct v4l2_rect image_win; |
---|
1896 | | - |
---|
1897 | | - vpfe_dbg(2, vpfe, "vpfe_calculate_offsets\n"); |
---|
1898 | 1754 | |
---|
1899 | 1755 | vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win); |
---|
1900 | 1756 | vpfe->field_off = image_win.height * image_win.width; |
---|
.. | .. |
---|
1979 | 1835 | spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); |
---|
1980 | 1836 | } |
---|
1981 | 1837 | |
---|
| 1838 | +static void vpfe_return_all_buffers(struct vpfe_device *vpfe, |
---|
| 1839 | + enum vb2_buffer_state state) |
---|
| 1840 | +{ |
---|
| 1841 | + struct vpfe_cap_buffer *buf, *node; |
---|
| 1842 | + unsigned long flags; |
---|
| 1843 | + |
---|
| 1844 | + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); |
---|
| 1845 | + list_for_each_entry_safe(buf, node, &vpfe->dma_queue, list) { |
---|
| 1846 | + vb2_buffer_done(&buf->vb.vb2_buf, state); |
---|
| 1847 | + list_del(&buf->list); |
---|
| 1848 | + } |
---|
| 1849 | + |
---|
| 1850 | + if (vpfe->cur_frm) |
---|
| 1851 | + vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf, state); |
---|
| 1852 | + |
---|
| 1853 | + if (vpfe->next_frm && vpfe->next_frm != vpfe->cur_frm) |
---|
| 1854 | + vb2_buffer_done(&vpfe->next_frm->vb.vb2_buf, state); |
---|
| 1855 | + |
---|
| 1856 | + vpfe->cur_frm = NULL; |
---|
| 1857 | + vpfe->next_frm = NULL; |
---|
| 1858 | + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); |
---|
| 1859 | +} |
---|
| 1860 | + |
---|
1982 | 1861 | /* |
---|
1983 | 1862 | * vpfe_start_streaming : Starts the DMA engine for streaming |
---|
1984 | 1863 | * @vb: ptr to vb2_buffer |
---|
.. | .. |
---|
1987 | 1866 | static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) |
---|
1988 | 1867 | { |
---|
1989 | 1868 | struct vpfe_device *vpfe = vb2_get_drv_priv(vq); |
---|
1990 | | - struct vpfe_cap_buffer *buf, *tmp; |
---|
1991 | 1869 | struct vpfe_subdev_info *sdinfo; |
---|
1992 | 1870 | unsigned long flags; |
---|
1993 | 1871 | unsigned long addr; |
---|
.. | .. |
---|
2001 | 1879 | sdinfo = vpfe->current_subdev; |
---|
2002 | 1880 | |
---|
2003 | 1881 | vpfe_attach_irq(vpfe); |
---|
| 1882 | + |
---|
| 1883 | + vpfe->stopping = false; |
---|
| 1884 | + init_completion(&vpfe->capture_stop); |
---|
2004 | 1885 | |
---|
2005 | 1886 | if (vpfe->ccdc.ccdc_cfg.if_type == VPFE_RAW_BAYER) |
---|
2006 | 1887 | vpfe_ccdc_config_raw(&vpfe->ccdc); |
---|
.. | .. |
---|
2030 | 1911 | return 0; |
---|
2031 | 1912 | |
---|
2032 | 1913 | err: |
---|
2033 | | - list_for_each_entry_safe(buf, tmp, &vpfe->dma_queue, list) { |
---|
2034 | | - list_del(&buf->list); |
---|
2035 | | - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); |
---|
2036 | | - } |
---|
2037 | | - |
---|
| 1914 | + vpfe_return_all_buffers(vpfe, VB2_BUF_STATE_QUEUED); |
---|
| 1915 | + vpfe_pcr_enable(&vpfe->ccdc, 0); |
---|
2038 | 1916 | return ret; |
---|
2039 | 1917 | } |
---|
2040 | 1918 | |
---|
.. | .. |
---|
2049 | 1927 | { |
---|
2050 | 1928 | struct vpfe_device *vpfe = vb2_get_drv_priv(vq); |
---|
2051 | 1929 | struct vpfe_subdev_info *sdinfo; |
---|
2052 | | - unsigned long flags; |
---|
2053 | 1930 | int ret; |
---|
2054 | 1931 | |
---|
2055 | 1932 | vpfe_pcr_enable(&vpfe->ccdc, 0); |
---|
| 1933 | + |
---|
| 1934 | + /* Wait for the last frame to be captured */ |
---|
| 1935 | + vpfe->stopping = true; |
---|
| 1936 | + wait_for_completion_timeout(&vpfe->capture_stop, |
---|
| 1937 | + msecs_to_jiffies(250)); |
---|
2056 | 1938 | |
---|
2057 | 1939 | vpfe_detach_irq(vpfe); |
---|
2058 | 1940 | |
---|
.. | .. |
---|
2062 | 1944 | vpfe_dbg(1, vpfe, "stream off failed in subdev\n"); |
---|
2063 | 1945 | |
---|
2064 | 1946 | /* release all active buffers */ |
---|
2065 | | - spin_lock_irqsave(&vpfe->dma_queue_lock, flags); |
---|
2066 | | - if (vpfe->cur_frm == vpfe->next_frm) { |
---|
2067 | | - vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf, |
---|
2068 | | - VB2_BUF_STATE_ERROR); |
---|
2069 | | - } else { |
---|
2070 | | - if (vpfe->cur_frm != NULL) |
---|
2071 | | - vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf, |
---|
2072 | | - VB2_BUF_STATE_ERROR); |
---|
2073 | | - if (vpfe->next_frm != NULL) |
---|
2074 | | - vb2_buffer_done(&vpfe->next_frm->vb.vb2_buf, |
---|
2075 | | - VB2_BUF_STATE_ERROR); |
---|
2076 | | - } |
---|
2077 | | - |
---|
2078 | | - while (!list_empty(&vpfe->dma_queue)) { |
---|
2079 | | - vpfe->next_frm = list_entry(vpfe->dma_queue.next, |
---|
2080 | | - struct vpfe_cap_buffer, list); |
---|
2081 | | - list_del(&vpfe->next_frm->list); |
---|
2082 | | - vb2_buffer_done(&vpfe->next_frm->vb.vb2_buf, |
---|
2083 | | - VB2_BUF_STATE_ERROR); |
---|
2084 | | - } |
---|
2085 | | - spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); |
---|
| 1947 | + vpfe_return_all_buffers(vpfe, VB2_BUF_STATE_ERROR); |
---|
2086 | 1948 | } |
---|
2087 | 1949 | |
---|
2088 | | -static int vpfe_cropcap(struct file *file, void *priv, |
---|
2089 | | - struct v4l2_cropcap *crop) |
---|
| 1950 | +static int vpfe_g_pixelaspect(struct file *file, void *priv, |
---|
| 1951 | + int type, struct v4l2_fract *f) |
---|
2090 | 1952 | { |
---|
2091 | 1953 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
2092 | 1954 | |
---|
2093 | | - vpfe_dbg(2, vpfe, "vpfe_cropcap\n"); |
---|
2094 | | - |
---|
2095 | | - if (vpfe->std_index >= ARRAY_SIZE(vpfe_standards)) |
---|
| 1955 | + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || |
---|
| 1956 | + vpfe->std_index >= ARRAY_SIZE(vpfe_standards)) |
---|
2096 | 1957 | return -EINVAL; |
---|
2097 | 1958 | |
---|
2098 | | - memset(crop, 0, sizeof(struct v4l2_cropcap)); |
---|
2099 | | - |
---|
2100 | | - crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
---|
2101 | | - crop->defrect.width = vpfe_standards[vpfe->std_index].width; |
---|
2102 | | - crop->bounds.width = crop->defrect.width; |
---|
2103 | | - crop->defrect.height = vpfe_standards[vpfe->std_index].height; |
---|
2104 | | - crop->bounds.height = crop->defrect.height; |
---|
2105 | | - crop->pixelaspect = vpfe_standards[vpfe->std_index].pixelaspect; |
---|
| 1959 | + *f = vpfe_standards[vpfe->std_index].pixelaspect; |
---|
2106 | 1960 | |
---|
2107 | 1961 | return 0; |
---|
2108 | 1962 | } |
---|
.. | .. |
---|
2112 | 1966 | { |
---|
2113 | 1967 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
2114 | 1968 | |
---|
| 1969 | + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || |
---|
| 1970 | + vpfe->std_index >= ARRAY_SIZE(vpfe_standards)) |
---|
| 1971 | + return -EINVAL; |
---|
| 1972 | + |
---|
2115 | 1973 | switch (s->target) { |
---|
2116 | 1974 | case V4L2_SEL_TGT_CROP_BOUNDS: |
---|
2117 | 1975 | case V4L2_SEL_TGT_CROP_DEFAULT: |
---|
2118 | | - s->r.left = s->r.top = 0; |
---|
2119 | | - s->r.width = vpfe->crop.width; |
---|
2120 | | - s->r.height = vpfe->crop.height; |
---|
| 1976 | + s->r.left = 0; |
---|
| 1977 | + s->r.top = 0; |
---|
| 1978 | + s->r.width = vpfe_standards[vpfe->std_index].width; |
---|
| 1979 | + s->r.height = vpfe_standards[vpfe->std_index].height; |
---|
2121 | 1980 | break; |
---|
2122 | 1981 | |
---|
2123 | 1982 | case V4L2_SEL_TGT_CROP: |
---|
.. | .. |
---|
2131 | 1990 | return 0; |
---|
2132 | 1991 | } |
---|
2133 | 1992 | |
---|
2134 | | -static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) |
---|
2135 | | -{ |
---|
2136 | | - if (a->left < b->left || a->top < b->top) |
---|
2137 | | - return 0; |
---|
2138 | | - |
---|
2139 | | - if (a->left + a->width > b->left + b->width) |
---|
2140 | | - return 0; |
---|
2141 | | - |
---|
2142 | | - if (a->top + a->height > b->top + b->height) |
---|
2143 | | - return 0; |
---|
2144 | | - |
---|
2145 | | - return 1; |
---|
2146 | | -} |
---|
2147 | | - |
---|
2148 | 1993 | static int |
---|
2149 | 1994 | vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) |
---|
2150 | 1995 | { |
---|
2151 | 1996 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
2152 | 1997 | struct v4l2_rect cr = vpfe->crop; |
---|
2153 | 1998 | struct v4l2_rect r = s->r; |
---|
| 1999 | + u32 bpp; |
---|
2154 | 2000 | |
---|
2155 | 2001 | /* If streaming is started, return error */ |
---|
2156 | 2002 | if (vb2_is_busy(&vpfe->buffer_queue)) { |
---|
.. | .. |
---|
2168 | 2014 | r.left = clamp_t(unsigned int, r.left, 0, cr.width - r.width); |
---|
2169 | 2015 | r.top = clamp_t(unsigned int, r.top, 0, cr.height - r.height); |
---|
2170 | 2016 | |
---|
2171 | | - if (s->flags & V4L2_SEL_FLAG_LE && !enclosed_rectangle(&r, &s->r)) |
---|
| 2017 | + if (s->flags & V4L2_SEL_FLAG_LE && !v4l2_rect_enclosed(&r, &s->r)) |
---|
2172 | 2018 | return -ERANGE; |
---|
2173 | 2019 | |
---|
2174 | | - if (s->flags & V4L2_SEL_FLAG_GE && !enclosed_rectangle(&s->r, &r)) |
---|
| 2020 | + if (s->flags & V4L2_SEL_FLAG_GE && !v4l2_rect_enclosed(&s->r, &r)) |
---|
2175 | 2021 | return -ERANGE; |
---|
2176 | 2022 | |
---|
2177 | 2023 | s->r = vpfe->crop = r; |
---|
2178 | 2024 | |
---|
2179 | | - vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, vpfe->bpp); |
---|
| 2025 | + bpp = __get_bytesperpixel(vpfe, vpfe->current_vpfe_fmt); |
---|
| 2026 | + vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, bpp); |
---|
2180 | 2027 | vpfe->fmt.fmt.pix.width = r.width; |
---|
2181 | 2028 | vpfe->fmt.fmt.pix.height = r.height; |
---|
2182 | | - vpfe->fmt.fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc); |
---|
| 2029 | + vpfe->fmt.fmt.pix.bytesperline = |
---|
| 2030 | + vpfe_ccdc_get_line_length(&vpfe->ccdc); |
---|
2183 | 2031 | vpfe->fmt.fmt.pix.sizeimage = vpfe->fmt.fmt.pix.bytesperline * |
---|
2184 | 2032 | vpfe->fmt.fmt.pix.height; |
---|
2185 | 2033 | |
---|
.. | .. |
---|
2194 | 2042 | { |
---|
2195 | 2043 | struct vpfe_device *vpfe = video_drvdata(file); |
---|
2196 | 2044 | int ret; |
---|
2197 | | - |
---|
2198 | | - vpfe_dbg(2, vpfe, "vpfe_ioctl_default\n"); |
---|
2199 | 2045 | |
---|
2200 | 2046 | if (!valid_prio) { |
---|
2201 | 2047 | vpfe_err(vpfe, "%s device busy\n", __func__); |
---|
.. | .. |
---|
2286 | 2132 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
---|
2287 | 2133 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
---|
2288 | 2134 | |
---|
2289 | | - .vidioc_cropcap = vpfe_cropcap, |
---|
| 2135 | + .vidioc_g_pixelaspect = vpfe_g_pixelaspect, |
---|
2290 | 2136 | .vidioc_g_selection = vpfe_g_selection, |
---|
2291 | 2137 | .vidioc_s_selection = vpfe_s_selection, |
---|
2292 | 2138 | |
---|
.. | .. |
---|
2302 | 2148 | struct vpfe_device, v4l2_dev); |
---|
2303 | 2149 | struct v4l2_subdev_mbus_code_enum mbus_code; |
---|
2304 | 2150 | struct vpfe_subdev_info *sdinfo; |
---|
| 2151 | + struct vpfe_fmt *fmt; |
---|
| 2152 | + int ret = 0; |
---|
2305 | 2153 | bool found = false; |
---|
2306 | | - int i, j; |
---|
2307 | | - |
---|
2308 | | - vpfe_dbg(1, vpfe, "vpfe_async_bound\n"); |
---|
| 2154 | + int i, j, k; |
---|
2309 | 2155 | |
---|
2310 | 2156 | for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { |
---|
2311 | 2157 | if (vpfe->cfg->asd[i]->match.fwnode == |
---|
.. | .. |
---|
2325 | 2171 | |
---|
2326 | 2172 | vpfe->video_dev.tvnorms |= sdinfo->inputs[0].std; |
---|
2327 | 2173 | |
---|
2328 | | - /* setup the supported formats & indexes */ |
---|
2329 | | - for (j = 0, i = 0; ; ++j) { |
---|
2330 | | - struct vpfe_fmt *fmt; |
---|
2331 | | - int ret; |
---|
2332 | | - |
---|
| 2174 | + vpfe->num_active_fmt = 0; |
---|
| 2175 | + for (j = 0, i = 0; (ret != -EINVAL); ++j) { |
---|
2333 | 2176 | memset(&mbus_code, 0, sizeof(mbus_code)); |
---|
2334 | 2177 | mbus_code.index = j; |
---|
2335 | 2178 | mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
---|
2336 | 2179 | ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, |
---|
2337 | | - NULL, &mbus_code); |
---|
| 2180 | + NULL, &mbus_code); |
---|
2338 | 2181 | if (ret) |
---|
2339 | | - break; |
---|
2340 | | - |
---|
2341 | | - fmt = find_format_by_code(mbus_code.code); |
---|
2342 | | - if (!fmt) |
---|
2343 | 2182 | continue; |
---|
2344 | 2183 | |
---|
2345 | | - fmt->supported = true; |
---|
2346 | | - fmt->index = i++; |
---|
| 2184 | + vpfe_dbg(3, vpfe, |
---|
| 2185 | + "subdev %s: code: %04x idx: %d\n", |
---|
| 2186 | + subdev->name, mbus_code.code, j); |
---|
| 2187 | + |
---|
| 2188 | + for (k = 0; k < ARRAY_SIZE(formats); k++) { |
---|
| 2189 | + fmt = &formats[k]; |
---|
| 2190 | + if (mbus_code.code != fmt->code) |
---|
| 2191 | + continue; |
---|
| 2192 | + vpfe->active_fmt[i] = fmt; |
---|
| 2193 | + vpfe_dbg(3, vpfe, |
---|
| 2194 | + "matched fourcc: %s code: %04x idx: %d\n", |
---|
| 2195 | + print_fourcc(fmt->fourcc), mbus_code.code, i); |
---|
| 2196 | + vpfe->num_active_fmt = ++i; |
---|
| 2197 | + } |
---|
2347 | 2198 | } |
---|
2348 | 2199 | |
---|
| 2200 | + if (!i) { |
---|
| 2201 | + vpfe_err(vpfe, "No suitable format reported by subdev %s\n", |
---|
| 2202 | + subdev->name); |
---|
| 2203 | + return -EINVAL; |
---|
| 2204 | + } |
---|
2349 | 2205 | return 0; |
---|
2350 | 2206 | } |
---|
2351 | 2207 | |
---|
.. | .. |
---|
2390 | 2246 | INIT_LIST_HEAD(&vpfe->dma_queue); |
---|
2391 | 2247 | |
---|
2392 | 2248 | vdev = &vpfe->video_dev; |
---|
2393 | | - strlcpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name)); |
---|
| 2249 | + strscpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name)); |
---|
2394 | 2250 | vdev->release = video_device_release_empty; |
---|
2395 | 2251 | vdev->fops = &vpfe_fops; |
---|
2396 | 2252 | vdev->ioctl_ops = &vpfe_ioctl_ops; |
---|
.. | .. |
---|
2398 | 2254 | vdev->vfl_dir = VFL_DIR_RX; |
---|
2399 | 2255 | vdev->queue = q; |
---|
2400 | 2256 | vdev->lock = &vpfe->lock; |
---|
| 2257 | + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | |
---|
| 2258 | + V4L2_CAP_READWRITE; |
---|
2401 | 2259 | video_set_drvdata(vdev, vpfe); |
---|
2402 | | - err = video_register_device(&vpfe->video_dev, VFL_TYPE_GRABBER, -1); |
---|
| 2260 | + err = video_register_device(&vpfe->video_dev, VFL_TYPE_VIDEO, -1); |
---|
2403 | 2261 | if (err) { |
---|
2404 | 2262 | vpfe_err(vpfe, |
---|
2405 | 2263 | "Unable to register video device.\n"); |
---|
.. | .. |
---|
2427 | 2285 | }; |
---|
2428 | 2286 | |
---|
2429 | 2287 | static struct vpfe_config * |
---|
2430 | | -vpfe_get_pdata(struct platform_device *pdev) |
---|
| 2288 | +vpfe_get_pdata(struct vpfe_device *vpfe) |
---|
2431 | 2289 | { |
---|
2432 | 2290 | struct device_node *endpoint = NULL; |
---|
2433 | | - struct v4l2_fwnode_endpoint bus_cfg; |
---|
| 2291 | + struct device *dev = vpfe->pdev; |
---|
2434 | 2292 | struct vpfe_subdev_info *sdinfo; |
---|
2435 | 2293 | struct vpfe_config *pdata; |
---|
2436 | 2294 | unsigned int flags; |
---|
2437 | 2295 | unsigned int i; |
---|
2438 | 2296 | int err; |
---|
2439 | 2297 | |
---|
2440 | | - dev_dbg(&pdev->dev, "vpfe_get_pdata\n"); |
---|
| 2298 | + dev_dbg(dev, "vpfe_get_pdata\n"); |
---|
2441 | 2299 | |
---|
2442 | | - if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) |
---|
2443 | | - return pdev->dev.platform_data; |
---|
| 2300 | + v4l2_async_notifier_init(&vpfe->notifier); |
---|
2444 | 2301 | |
---|
2445 | | - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
---|
| 2302 | + if (!IS_ENABLED(CONFIG_OF) || !dev->of_node) |
---|
| 2303 | + return dev->platform_data; |
---|
| 2304 | + |
---|
| 2305 | + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); |
---|
2446 | 2306 | if (!pdata) |
---|
2447 | 2307 | return NULL; |
---|
2448 | 2308 | |
---|
2449 | 2309 | for (i = 0; ; i++) { |
---|
| 2310 | + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; |
---|
2450 | 2311 | struct device_node *rem; |
---|
2451 | 2312 | |
---|
2452 | | - endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, |
---|
2453 | | - endpoint); |
---|
| 2313 | + endpoint = of_graph_get_next_endpoint(dev->of_node, endpoint); |
---|
2454 | 2314 | if (!endpoint) |
---|
2455 | 2315 | break; |
---|
2456 | 2316 | |
---|
.. | .. |
---|
2459 | 2319 | |
---|
2460 | 2320 | /* we only support camera */ |
---|
2461 | 2321 | sdinfo->inputs[0].index = i; |
---|
2462 | | - strcpy(sdinfo->inputs[0].name, "Camera"); |
---|
| 2322 | + strscpy(sdinfo->inputs[0].name, "Camera", |
---|
| 2323 | + sizeof(sdinfo->inputs[0].name)); |
---|
2463 | 2324 | sdinfo->inputs[0].type = V4L2_INPUT_TYPE_CAMERA; |
---|
2464 | 2325 | sdinfo->inputs[0].std = V4L2_STD_ALL; |
---|
2465 | 2326 | sdinfo->inputs[0].capabilities = V4L2_IN_CAP_STD; |
---|
.. | .. |
---|
2477 | 2338 | err = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), |
---|
2478 | 2339 | &bus_cfg); |
---|
2479 | 2340 | if (err) { |
---|
2480 | | - dev_err(&pdev->dev, "Could not parse the endpoint\n"); |
---|
2481 | | - goto done; |
---|
| 2341 | + dev_err(dev, "Could not parse the endpoint\n"); |
---|
| 2342 | + goto cleanup; |
---|
2482 | 2343 | } |
---|
2483 | 2344 | |
---|
2484 | 2345 | sdinfo->vpfe_param.bus_width = bus_cfg.bus.parallel.bus_width; |
---|
2485 | 2346 | |
---|
2486 | 2347 | if (sdinfo->vpfe_param.bus_width < 8 || |
---|
2487 | 2348 | sdinfo->vpfe_param.bus_width > 16) { |
---|
2488 | | - dev_err(&pdev->dev, "Invalid bus width.\n"); |
---|
2489 | | - goto done; |
---|
| 2349 | + dev_err(dev, "Invalid bus width.\n"); |
---|
| 2350 | + goto cleanup; |
---|
2490 | 2351 | } |
---|
2491 | 2352 | |
---|
2492 | 2353 | flags = bus_cfg.bus.parallel.flags; |
---|
.. | .. |
---|
2499 | 2360 | |
---|
2500 | 2361 | rem = of_graph_get_remote_port_parent(endpoint); |
---|
2501 | 2362 | if (!rem) { |
---|
2502 | | - dev_err(&pdev->dev, "Remote device at %pOF not found\n", |
---|
| 2363 | + dev_err(dev, "Remote device at %pOF not found\n", |
---|
2503 | 2364 | endpoint); |
---|
2504 | | - goto done; |
---|
| 2365 | + goto cleanup; |
---|
2505 | 2366 | } |
---|
2506 | 2367 | |
---|
2507 | | - pdata->asd[i] = devm_kzalloc(&pdev->dev, |
---|
2508 | | - sizeof(struct v4l2_async_subdev), |
---|
2509 | | - GFP_KERNEL); |
---|
2510 | | - if (!pdata->asd[i]) { |
---|
2511 | | - of_node_put(rem); |
---|
2512 | | - pdata = NULL; |
---|
2513 | | - goto done; |
---|
2514 | | - } |
---|
2515 | | - |
---|
2516 | | - pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_FWNODE; |
---|
2517 | | - pdata->asd[i]->match.fwnode = of_fwnode_handle(rem); |
---|
| 2368 | + pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev( |
---|
| 2369 | + &vpfe->notifier, of_fwnode_handle(rem), |
---|
| 2370 | + sizeof(struct v4l2_async_subdev)); |
---|
2518 | 2371 | of_node_put(rem); |
---|
| 2372 | + if (IS_ERR(pdata->asd[i])) |
---|
| 2373 | + goto cleanup; |
---|
2519 | 2374 | } |
---|
2520 | 2375 | |
---|
2521 | 2376 | of_node_put(endpoint); |
---|
2522 | 2377 | return pdata; |
---|
2523 | 2378 | |
---|
2524 | | -done: |
---|
| 2379 | +cleanup: |
---|
| 2380 | + v4l2_async_notifier_cleanup(&vpfe->notifier); |
---|
2525 | 2381 | of_node_put(endpoint); |
---|
2526 | 2382 | return NULL; |
---|
2527 | 2383 | } |
---|
.. | .. |
---|
2533 | 2389 | */ |
---|
2534 | 2390 | static int vpfe_probe(struct platform_device *pdev) |
---|
2535 | 2391 | { |
---|
2536 | | - struct vpfe_config *vpfe_cfg = vpfe_get_pdata(pdev); |
---|
| 2392 | + struct vpfe_config *vpfe_cfg; |
---|
2537 | 2393 | struct vpfe_device *vpfe; |
---|
2538 | 2394 | struct vpfe_ccdc *ccdc; |
---|
2539 | 2395 | struct resource *res; |
---|
2540 | 2396 | int ret; |
---|
2541 | | - |
---|
2542 | | - if (!vpfe_cfg) { |
---|
2543 | | - dev_err(&pdev->dev, "No platform data\n"); |
---|
2544 | | - return -EINVAL; |
---|
2545 | | - } |
---|
2546 | 2397 | |
---|
2547 | 2398 | vpfe = devm_kzalloc(&pdev->dev, sizeof(*vpfe), GFP_KERNEL); |
---|
2548 | 2399 | if (!vpfe) |
---|
2549 | 2400 | return -ENOMEM; |
---|
2550 | 2401 | |
---|
2551 | 2402 | vpfe->pdev = &pdev->dev; |
---|
| 2403 | + |
---|
| 2404 | + vpfe_cfg = vpfe_get_pdata(vpfe); |
---|
| 2405 | + if (!vpfe_cfg) { |
---|
| 2406 | + dev_err(&pdev->dev, "No platform data\n"); |
---|
| 2407 | + return -EINVAL; |
---|
| 2408 | + } |
---|
| 2409 | + |
---|
2552 | 2410 | vpfe->cfg = vpfe_cfg; |
---|
2553 | 2411 | ccdc = &vpfe->ccdc; |
---|
2554 | 2412 | |
---|
2555 | 2413 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
2556 | 2414 | ccdc->ccdc_cfg.base_addr = devm_ioremap_resource(&pdev->dev, res); |
---|
2557 | | - if (IS_ERR(ccdc->ccdc_cfg.base_addr)) |
---|
2558 | | - return PTR_ERR(ccdc->ccdc_cfg.base_addr); |
---|
| 2415 | + if (IS_ERR(ccdc->ccdc_cfg.base_addr)) { |
---|
| 2416 | + ret = PTR_ERR(ccdc->ccdc_cfg.base_addr); |
---|
| 2417 | + goto probe_out_cleanup; |
---|
| 2418 | + } |
---|
2559 | 2419 | |
---|
2560 | 2420 | ret = platform_get_irq(pdev, 0); |
---|
2561 | 2421 | if (ret <= 0) { |
---|
2562 | | - dev_err(&pdev->dev, "No IRQ resource\n"); |
---|
2563 | | - return -ENODEV; |
---|
| 2422 | + ret = -ENODEV; |
---|
| 2423 | + goto probe_out_cleanup; |
---|
2564 | 2424 | } |
---|
2565 | 2425 | vpfe->irq = ret; |
---|
2566 | 2426 | |
---|
.. | .. |
---|
2568 | 2428 | "vpfe_capture0", vpfe); |
---|
2569 | 2429 | if (ret) { |
---|
2570 | 2430 | dev_err(&pdev->dev, "Unable to request interrupt\n"); |
---|
2571 | | - return -EINVAL; |
---|
| 2431 | + ret = -EINVAL; |
---|
| 2432 | + goto probe_out_cleanup; |
---|
2572 | 2433 | } |
---|
2573 | 2434 | |
---|
2574 | 2435 | ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev); |
---|
2575 | 2436 | if (ret) { |
---|
2576 | 2437 | vpfe_err(vpfe, |
---|
2577 | 2438 | "Unable to register v4l2 device.\n"); |
---|
2578 | | - return ret; |
---|
| 2439 | + goto probe_out_cleanup; |
---|
2579 | 2440 | } |
---|
2580 | 2441 | |
---|
2581 | 2442 | /* set the driver data in platform device */ |
---|
.. | .. |
---|
2584 | 2445 | pm_runtime_enable(&pdev->dev); |
---|
2585 | 2446 | |
---|
2586 | 2447 | /* for now just enable it here instead of waiting for the open */ |
---|
2587 | | - pm_runtime_get_sync(&pdev->dev); |
---|
| 2448 | + ret = pm_runtime_resume_and_get(&pdev->dev); |
---|
| 2449 | + if (ret < 0) { |
---|
| 2450 | + vpfe_err(vpfe, "Unable to resume device.\n"); |
---|
| 2451 | + goto probe_out_v4l2_unregister; |
---|
| 2452 | + } |
---|
2588 | 2453 | |
---|
2589 | 2454 | vpfe_ccdc_config_defaults(ccdc); |
---|
2590 | 2455 | |
---|
.. | .. |
---|
2599 | 2464 | goto probe_out_v4l2_unregister; |
---|
2600 | 2465 | } |
---|
2601 | 2466 | |
---|
2602 | | - vpfe->notifier.subdevs = vpfe->cfg->asd; |
---|
2603 | | - vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd); |
---|
2604 | 2467 | vpfe->notifier.ops = &vpfe_async_ops; |
---|
2605 | | - ret = v4l2_async_notifier_register(&vpfe->v4l2_dev, |
---|
2606 | | - &vpfe->notifier); |
---|
| 2468 | + ret = v4l2_async_notifier_register(&vpfe->v4l2_dev, &vpfe->notifier); |
---|
2607 | 2469 | if (ret) { |
---|
2608 | 2470 | vpfe_err(vpfe, "Error registering async notifier\n"); |
---|
2609 | 2471 | ret = -EINVAL; |
---|
.. | .. |
---|
2614 | 2476 | |
---|
2615 | 2477 | probe_out_v4l2_unregister: |
---|
2616 | 2478 | v4l2_device_unregister(&vpfe->v4l2_dev); |
---|
| 2479 | +probe_out_cleanup: |
---|
| 2480 | + v4l2_async_notifier_cleanup(&vpfe->notifier); |
---|
2617 | 2481 | return ret; |
---|
2618 | 2482 | } |
---|
2619 | 2483 | |
---|
.. | .. |
---|
2624 | 2488 | { |
---|
2625 | 2489 | struct vpfe_device *vpfe = platform_get_drvdata(pdev); |
---|
2626 | 2490 | |
---|
2627 | | - vpfe_dbg(2, vpfe, "vpfe_remove\n"); |
---|
2628 | | - |
---|
2629 | 2491 | pm_runtime_disable(&pdev->dev); |
---|
2630 | 2492 | |
---|
2631 | 2493 | v4l2_async_notifier_unregister(&vpfe->notifier); |
---|
| 2494 | + v4l2_async_notifier_cleanup(&vpfe->notifier); |
---|
2632 | 2495 | v4l2_device_unregister(&vpfe->v4l2_dev); |
---|
2633 | 2496 | video_unregister_device(&vpfe->video_dev); |
---|
2634 | 2497 | |
---|
.. | .. |
---|
2671 | 2534 | struct vpfe_device *vpfe = dev_get_drvdata(dev); |
---|
2672 | 2535 | struct vpfe_ccdc *ccdc = &vpfe->ccdc; |
---|
2673 | 2536 | |
---|
2674 | | - /* if streaming has not started we don't care */ |
---|
2675 | | - if (!vb2_start_streaming_called(&vpfe->buffer_queue)) |
---|
2676 | | - return 0; |
---|
| 2537 | + /* only do full suspend if streaming has started */ |
---|
| 2538 | + if (vb2_start_streaming_called(&vpfe->buffer_queue)) { |
---|
| 2539 | + /* |
---|
| 2540 | + * ignore RPM resume errors here, as it is already too late. |
---|
| 2541 | + * A check like that should happen earlier, either at |
---|
| 2542 | + * open() or just before start streaming. |
---|
| 2543 | + */ |
---|
| 2544 | + pm_runtime_get_sync(dev); |
---|
| 2545 | + vpfe_config_enable(ccdc, 1); |
---|
2677 | 2546 | |
---|
2678 | | - pm_runtime_get_sync(dev); |
---|
2679 | | - vpfe_config_enable(ccdc, 1); |
---|
| 2547 | + /* Save VPFE context */ |
---|
| 2548 | + vpfe_save_context(ccdc); |
---|
2680 | 2549 | |
---|
2681 | | - /* Save VPFE context */ |
---|
2682 | | - vpfe_save_context(ccdc); |
---|
| 2550 | + /* Disable CCDC */ |
---|
| 2551 | + vpfe_pcr_enable(ccdc, 0); |
---|
| 2552 | + vpfe_config_enable(ccdc, 0); |
---|
2683 | 2553 | |
---|
2684 | | - /* Disable CCDC */ |
---|
2685 | | - vpfe_pcr_enable(ccdc, 0); |
---|
2686 | | - vpfe_config_enable(ccdc, 0); |
---|
2687 | | - |
---|
2688 | | - /* Disable both master and slave clock */ |
---|
2689 | | - pm_runtime_put_sync(dev); |
---|
| 2554 | + /* Disable both master and slave clock */ |
---|
| 2555 | + pm_runtime_put_sync(dev); |
---|
| 2556 | + } |
---|
2690 | 2557 | |
---|
2691 | 2558 | /* Select sleep pin state */ |
---|
2692 | 2559 | pinctrl_pm_select_sleep_state(dev); |
---|
.. | .. |
---|
2728 | 2595 | struct vpfe_device *vpfe = dev_get_drvdata(dev); |
---|
2729 | 2596 | struct vpfe_ccdc *ccdc = &vpfe->ccdc; |
---|
2730 | 2597 | |
---|
2731 | | - /* if streaming has not started we don't care */ |
---|
2732 | | - if (!vb2_start_streaming_called(&vpfe->buffer_queue)) |
---|
2733 | | - return 0; |
---|
| 2598 | + /* only do full resume if streaming has started */ |
---|
| 2599 | + if (vb2_start_streaming_called(&vpfe->buffer_queue)) { |
---|
| 2600 | + /* Enable both master and slave clock */ |
---|
| 2601 | + pm_runtime_get_sync(dev); |
---|
| 2602 | + vpfe_config_enable(ccdc, 1); |
---|
2734 | 2603 | |
---|
2735 | | - /* Enable both master and slave clock */ |
---|
2736 | | - pm_runtime_get_sync(dev); |
---|
2737 | | - vpfe_config_enable(ccdc, 1); |
---|
| 2604 | + /* Restore VPFE context */ |
---|
| 2605 | + vpfe_restore_context(ccdc); |
---|
2738 | 2606 | |
---|
2739 | | - /* Restore VPFE context */ |
---|
2740 | | - vpfe_restore_context(ccdc); |
---|
2741 | | - |
---|
2742 | | - vpfe_config_enable(ccdc, 0); |
---|
2743 | | - pm_runtime_put_sync(dev); |
---|
| 2607 | + vpfe_config_enable(ccdc, 0); |
---|
| 2608 | + pm_runtime_put_sync(dev); |
---|
| 2609 | + } |
---|
2744 | 2610 | |
---|
2745 | 2611 | /* Select default pin state */ |
---|
2746 | 2612 | pinctrl_pm_select_default_state(dev); |
---|