| .. | .. |
|---|
| 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); |
|---|