Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] media: platform: add VPFE capture driver support for AM437X

This patch adds Video Processing Front End (VPFE) driver for
AM437X family of devices
Driver supports the following:
- V4L2 API using MMAP buffer access based on videobuf2 api
- Asynchronous sensor/decoder sub device registration
- DT support

Signed-off-by: Benoit Parrot <bparrot@ti.com>
Signed-off-by: Darren Etheridge <detheridge@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.csengg@gmail.com>
[hans.verkuil@cisco.com: swapped two lines to fix vpfe_release() & add pinctrl include]
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

authored by

Benoit Parrot and committed by
Mauro Carvalho Chehab
417d2e50 3b1635e0

+3411
+61
Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt
··· 1 + Texas Instruments AM437x CAMERA (VPFE) 2 + -------------------------------------- 3 + 4 + The Video Processing Front End (VPFE) is a key component for image capture 5 + applications. The capture module provides the system interface and the 6 + processing capability to connect RAW image-sensor modules and video decoders 7 + to the AM437x device. 8 + 9 + Required properties: 10 + - compatible: must be "ti,am437x-vpfe" 11 + - reg: physical base address and length of the registers set for the device; 12 + - interrupts: should contain IRQ line for the VPFE; 13 + - ti,am437x-vpfe-interface: can be one of the following, 14 + 0 - Raw Bayer Interface. 15 + 1 - 8 Bit BT656 Interface. 16 + 2 - 10 Bit BT656 Interface. 17 + 3 - YCbCr 8 Bit Interface. 18 + 4 - YCbCr 16 Bit Interface. 19 + 20 + VPFE supports a single port node with parallel bus. It should contain one 21 + 'port' child node with child 'endpoint' node. Please refer to the bindings 22 + defined in Documentation/devicetree/bindings/media/video-interfaces.txt. 23 + 24 + Example: 25 + vpfe: vpfe@f0034000 { 26 + compatible = "ti,am437x-vpfe"; 27 + reg = <0x48328000 0x2000>; 28 + interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>; 29 + 30 + pinctrl-names = "default", "sleep"; 31 + pinctrl-0 = <&vpfe_pins_default>; 32 + pinctrl-1 = <&vpfe_pins_sleep>; 33 + 34 + port { 35 + #address-cells = <1>; 36 + #size-cells = <0>; 37 + 38 + vpfe0_ep: endpoint { 39 + remote-endpoint = <&ov2659_1>; 40 + ti,am437x-vpfe-interface = <0>; 41 + bus-width = <8>; 42 + hsync-active = <0>; 43 + vsync-active = <0>; 44 + }; 45 + }; 46 + }; 47 + 48 + i2c1: i2c@4802a000 { 49 + 50 + ov2659@30 { 51 + compatible = "ti,ov2659"; 52 + reg = <0x30>; 53 + 54 + port { 55 + ov2659_1: endpoint { 56 + remote-endpoint = <&vpfe0_ep>; 57 + bus-width = <8>; 58 + mclk-frequency = <12000000>; 59 + }; 60 + }; 61 + };
+9
MAINTAINERS
··· 8745 8745 F: drivers/media/platform/davinci/ 8746 8746 F: include/media/davinci/ 8747 8747 8748 + TI AM437X VPFE DRIVER 8749 + M: Lad, Prabhakar <prabhakar.csengg@gmail.com> 8750 + L: linux-media@vger.kernel.org 8751 + W: http://linuxtv.org/ 8752 + Q: http://patchwork.linuxtv.org/project/linux-media/list/ 8753 + T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git 8754 + S: Maintained 8755 + F: drivers/media/platform/am437x/ 8756 + 8748 8757 SIS 190 ETHERNET DRIVER 8749 8758 M: Francois Romieu <romieu@fr.zoreil.com> 8750 8759 L: netdev@vger.kernel.org
+1
drivers/media/platform/Kconfig
··· 118 118 source "drivers/media/platform/soc_camera/Kconfig" 119 119 source "drivers/media/platform/exynos4-is/Kconfig" 120 120 source "drivers/media/platform/s5p-tv/Kconfig" 121 + source "drivers/media/platform/am437x/Kconfig" 121 122 122 123 endif # V4L_PLATFORM_DRIVERS 123 124
+2
drivers/media/platform/Makefile
··· 46 46 47 47 obj-y += omap/ 48 48 49 + obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ 50 + 49 51 ccflags-y += -I$(srctree)/drivers/media/i2c
+11
drivers/media/platform/am437x/Kconfig
··· 1 + config VIDEO_AM437X_VPFE 2 + tristate "TI AM437x VPFE video capture driver" 3 + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API 4 + depends on SOC_AM43XX || COMPILE_TEST 5 + select VIDEOBUF2_DMA_CONTIG 6 + help 7 + Support for AM437x Video Processing Front End based Video 8 + Capture Driver. 9 + 10 + To compile this driver as a module, choose M here. The module 11 + will be called am437x-vpfe.
+3
drivers/media/platform/am437x/Makefile
··· 1 + # Makefile for AM437x VPFE driver 2 + 3 + obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x-vpfe.o
+2778
drivers/media/platform/am437x/am437x-vpfe.c
··· 1 + /* 2 + * TI VPFE capture Driver 3 + * 4 + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. 5 + * 6 + * Benoit Parrot <bparrot@ti.com> 7 + * 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 + */ 22 + 23 + #include <linux/delay.h> 24 + #include <linux/err.h> 25 + #include <linux/init.h> 26 + #include <linux/interrupt.h> 27 + #include <linux/io.h> 28 + #include <linux/module.h> 29 + #include <linux/pinctrl/consumer.h> 30 + #include <linux/platform_device.h> 31 + #include <linux/pm_runtime.h> 32 + #include <linux/slab.h> 33 + #include <linux/uaccess.h> 34 + #include <linux/videodev2.h> 35 + 36 + #include <media/v4l2-common.h> 37 + #include <media/v4l2-ctrls.h> 38 + #include <media/v4l2-event.h> 39 + #include <media/v4l2-of.h> 40 + 41 + #include "am437x-vpfe.h" 42 + 43 + #define VPFE_MODULE_NAME "vpfe" 44 + #define VPFE_VERSION "0.1.0" 45 + 46 + static int debug; 47 + module_param(debug, int, 0644); 48 + MODULE_PARM_DESC(debug, "Debug level 0-8"); 49 + 50 + #define vpfe_dbg(level, dev, fmt, arg...) \ 51 + v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ##arg) 52 + #define vpfe_info(dev, fmt, arg...) \ 53 + v4l2_info(&dev->v4l2_dev, fmt, ##arg) 54 + #define vpfe_err(dev, fmt, arg...) \ 55 + v4l2_err(&dev->v4l2_dev, fmt, ##arg) 56 + 57 + /* standard information */ 58 + struct vpfe_standard { 59 + v4l2_std_id std_id; 60 + unsigned int width; 61 + unsigned int height; 62 + struct v4l2_fract pixelaspect; 63 + int frame_format; 64 + }; 65 + 66 + const struct vpfe_standard vpfe_standards[] = { 67 + {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, 68 + {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, 69 + }; 70 + 71 + struct bus_format { 72 + unsigned int width; 73 + unsigned int bpp; 74 + }; 75 + 76 + /* 77 + * struct vpfe_fmt - VPFE media bus format information 78 + * @name: V4L2 format description 79 + * @code: V4L2 media bus format code 80 + * @shifted: V4L2 media bus format code for the same pixel layout but 81 + * shifted to be 8 bits per pixel. =0 if format is not shiftable. 82 + * @pixelformat: V4L2 pixel format FCC identifier 83 + * @width: Bits per pixel (when transferred over a bus) 84 + * @bpp: Bytes per pixel (when stored in memory) 85 + * @supported: Indicates format supported by subdev 86 + */ 87 + struct vpfe_fmt { 88 + const char *name; 89 + u32 fourcc; 90 + u32 code; 91 + struct bus_format l; 92 + struct bus_format s; 93 + bool supported; 94 + u32 index; 95 + }; 96 + 97 + static struct vpfe_fmt formats[] = { 98 + { 99 + .name = "YUV 4:2:2 packed, YCbYCr", 100 + .fourcc = V4L2_PIX_FMT_YUYV, 101 + .code = MEDIA_BUS_FMT_YUYV8_2X8, 102 + .l.width = 10, 103 + .l.bpp = 4, 104 + .s.width = 8, 105 + .s.bpp = 2, 106 + .supported = false, 107 + }, { 108 + .name = "YUV 4:2:2 packed, CbYCrY", 109 + .fourcc = V4L2_PIX_FMT_UYVY, 110 + .code = MEDIA_BUS_FMT_UYVY8_2X8, 111 + .l.width = 10, 112 + .l.bpp = 4, 113 + .s.width = 8, 114 + .s.bpp = 2, 115 + .supported = false, 116 + }, { 117 + .name = "YUV 4:2:2 packed, YCrYCb", 118 + .fourcc = V4L2_PIX_FMT_YVYU, 119 + .code = MEDIA_BUS_FMT_YVYU8_2X8, 120 + .l.width = 10, 121 + .l.bpp = 4, 122 + .s.width = 8, 123 + .s.bpp = 2, 124 + .supported = false, 125 + }, { 126 + .name = "YUV 4:2:2 packed, CrYCbY", 127 + .fourcc = V4L2_PIX_FMT_VYUY, 128 + .code = MEDIA_BUS_FMT_VYUY8_2X8, 129 + .l.width = 10, 130 + .l.bpp = 4, 131 + .s.width = 8, 132 + .s.bpp = 2, 133 + .supported = false, 134 + }, { 135 + .name = "RAW8 BGGR", 136 + .fourcc = V4L2_PIX_FMT_SBGGR8, 137 + .code = MEDIA_BUS_FMT_SBGGR8_1X8, 138 + .l.width = 10, 139 + .l.bpp = 2, 140 + .s.width = 8, 141 + .s.bpp = 1, 142 + .supported = false, 143 + }, { 144 + .name = "RAW8 GBRG", 145 + .fourcc = V4L2_PIX_FMT_SGBRG8, 146 + .code = MEDIA_BUS_FMT_SGBRG8_1X8, 147 + .l.width = 10, 148 + .l.bpp = 2, 149 + .s.width = 8, 150 + .s.bpp = 1, 151 + .supported = false, 152 + }, { 153 + .name = "RAW8 GRBG", 154 + .fourcc = V4L2_PIX_FMT_SGRBG8, 155 + .code = MEDIA_BUS_FMT_SGRBG8_1X8, 156 + .l.width = 10, 157 + .l.bpp = 2, 158 + .s.width = 8, 159 + .s.bpp = 1, 160 + .supported = false, 161 + }, { 162 + .name = "RAW8 RGGB", 163 + .fourcc = V4L2_PIX_FMT_SRGGB8, 164 + .code = MEDIA_BUS_FMT_SRGGB8_1X8, 165 + .l.width = 10, 166 + .l.bpp = 2, 167 + .s.width = 8, 168 + .s.bpp = 1, 169 + .supported = false, 170 + }, { 171 + .name = "RGB565 (LE)", 172 + .fourcc = V4L2_PIX_FMT_RGB565, 173 + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, 174 + .l.width = 10, 175 + .l.bpp = 4, 176 + .s.width = 8, 177 + .s.bpp = 2, 178 + .supported = false, 179 + }, { 180 + .name = "RGB565 (BE)", 181 + .fourcc = V4L2_PIX_FMT_RGB565X, 182 + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, 183 + .l.width = 10, 184 + .l.bpp = 4, 185 + .s.width = 8, 186 + .s.bpp = 2, 187 + .supported = false, 188 + }, 189 + }; 190 + 191 + static int 192 + __vpfe_get_format(struct vpfe_device *vpfe, 193 + struct v4l2_format *format, unsigned int *bpp); 194 + 195 + static struct vpfe_fmt *find_format_by_code(unsigned int code) 196 + { 197 + struct vpfe_fmt *fmt; 198 + unsigned int k; 199 + 200 + for (k = 0; k < ARRAY_SIZE(formats); k++) { 201 + fmt = &formats[k]; 202 + if (fmt->code == code) 203 + return fmt; 204 + } 205 + 206 + return NULL; 207 + } 208 + 209 + static struct vpfe_fmt *find_format_by_pix(unsigned int pixelformat) 210 + { 211 + struct vpfe_fmt *fmt; 212 + unsigned int k; 213 + 214 + for (k = 0; k < ARRAY_SIZE(formats); k++) { 215 + fmt = &formats[k]; 216 + if (fmt->fourcc == pixelformat) 217 + return fmt; 218 + } 219 + 220 + return NULL; 221 + } 222 + 223 + static void 224 + mbus_to_pix(struct vpfe_device *vpfe, 225 + const struct v4l2_mbus_framefmt *mbus, 226 + struct v4l2_pix_format *pix, unsigned int *bpp) 227 + { 228 + struct vpfe_subdev_info *sdinfo = vpfe->current_subdev; 229 + unsigned int bus_width = sdinfo->vpfe_param.bus_width; 230 + struct vpfe_fmt *fmt; 231 + 232 + fmt = find_format_by_code(mbus->code); 233 + if (WARN_ON(fmt == NULL)) { 234 + pr_err("Invalid mbus code set\n"); 235 + *bpp = 1; 236 + return; 237 + } 238 + 239 + memset(pix, 0, sizeof(*pix)); 240 + v4l2_fill_pix_format(pix, mbus); 241 + pix->pixelformat = fmt->fourcc; 242 + *bpp = (bus_width == 10) ? fmt->l.bpp : fmt->s.bpp; 243 + 244 + /* pitch should be 32 bytes aligned */ 245 + pix->bytesperline = ALIGN(pix->width * *bpp, 32); 246 + pix->sizeimage = pix->bytesperline * pix->height; 247 + } 248 + 249 + static void pix_to_mbus(struct vpfe_device *vpfe, 250 + struct v4l2_pix_format *pix_fmt, 251 + struct v4l2_mbus_framefmt *mbus_fmt) 252 + { 253 + struct vpfe_fmt *fmt; 254 + 255 + fmt = find_format_by_pix(pix_fmt->pixelformat); 256 + if (!fmt) { 257 + /* default to first entry */ 258 + vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", 259 + pix_fmt->pixelformat); 260 + fmt = &formats[0]; 261 + } 262 + 263 + memset(mbus_fmt, 0, sizeof(*mbus_fmt)); 264 + v4l2_fill_mbus_format(mbus_fmt, pix_fmt, fmt->code); 265 + } 266 + 267 + /* Print Four-character-code (FOURCC) */ 268 + static char *print_fourcc(u32 fmt) 269 + { 270 + static char code[5]; 271 + 272 + code[0] = (unsigned char)(fmt & 0xff); 273 + code[1] = (unsigned char)((fmt >> 8) & 0xff); 274 + code[2] = (unsigned char)((fmt >> 16) & 0xff); 275 + code[3] = (unsigned char)((fmt >> 24) & 0xff); 276 + code[4] = '\0'; 277 + 278 + return code; 279 + } 280 + 281 + static int 282 + cmp_v4l2_format(const struct v4l2_format *lhs, const struct v4l2_format *rhs) 283 + { 284 + return lhs->type == rhs->type && 285 + lhs->fmt.pix.width == rhs->fmt.pix.width && 286 + lhs->fmt.pix.height == rhs->fmt.pix.height && 287 + lhs->fmt.pix.pixelformat == rhs->fmt.pix.pixelformat && 288 + lhs->fmt.pix.field == rhs->fmt.pix.field && 289 + lhs->fmt.pix.colorspace == rhs->fmt.pix.colorspace && 290 + lhs->fmt.pix.ycbcr_enc == rhs->fmt.pix.ycbcr_enc && 291 + lhs->fmt.pix.quantization == rhs->fmt.pix.quantization; 292 + } 293 + 294 + static inline u32 vpfe_reg_read(struct vpfe_ccdc *ccdc, u32 offset) 295 + { 296 + return ioread32(ccdc->ccdc_cfg.base_addr + offset); 297 + } 298 + 299 + static inline void vpfe_reg_write(struct vpfe_ccdc *ccdc, u32 val, u32 offset) 300 + { 301 + iowrite32(val, ccdc->ccdc_cfg.base_addr + offset); 302 + } 303 + 304 + static inline struct vpfe_device *to_vpfe(struct vpfe_ccdc *ccdc) 305 + { 306 + return container_of(ccdc, struct vpfe_device, ccdc); 307 + } 308 + 309 + static inline struct vpfe_cap_buffer *to_vpfe_buffer(struct vb2_buffer *vb) 310 + { 311 + return container_of(vb, struct vpfe_cap_buffer, vb); 312 + } 313 + 314 + static inline void vpfe_pcr_enable(struct vpfe_ccdc *ccdc, int flag) 315 + { 316 + vpfe_reg_write(ccdc, !!flag, VPFE_PCR); 317 + } 318 + 319 + static void vpfe_config_enable(struct vpfe_ccdc *ccdc, int flag) 320 + { 321 + unsigned int cfg; 322 + 323 + if (!flag) { 324 + cfg = vpfe_reg_read(ccdc, VPFE_CONFIG); 325 + cfg &= ~(VPFE_CONFIG_EN_ENABLE << VPFE_CONFIG_EN_SHIFT); 326 + } else { 327 + cfg = VPFE_CONFIG_EN_ENABLE << VPFE_CONFIG_EN_SHIFT; 328 + } 329 + 330 + vpfe_reg_write(ccdc, cfg, VPFE_CONFIG); 331 + } 332 + 333 + static void vpfe_ccdc_setwin(struct vpfe_ccdc *ccdc, 334 + struct v4l2_rect *image_win, 335 + enum ccdc_frmfmt frm_fmt, 336 + int bpp) 337 + { 338 + int horz_start, horz_nr_pixels; 339 + int vert_start, vert_nr_lines; 340 + int val, mid_img; 341 + 342 + /* 343 + * ppc - per pixel count. indicates how many pixels per cell 344 + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. 345 + * raw capture this is 1 346 + */ 347 + horz_start = image_win->left * bpp; 348 + horz_nr_pixels = (image_win->width * bpp) - 1; 349 + vpfe_reg_write(ccdc, (horz_start << VPFE_HORZ_INFO_SPH_SHIFT) | 350 + horz_nr_pixels, VPFE_HORZ_INFO); 351 + 352 + vert_start = image_win->top; 353 + 354 + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { 355 + vert_nr_lines = (image_win->height >> 1) - 1; 356 + vert_start >>= 1; 357 + /* Since first line doesn't have any data */ 358 + vert_start += 1; 359 + /* configure VDINT0 */ 360 + val = (vert_start << VPFE_VDINT_VDINT0_SHIFT); 361 + } else { 362 + /* Since first line doesn't have any data */ 363 + vert_start += 1; 364 + vert_nr_lines = image_win->height - 1; 365 + /* 366 + * configure VDINT0 and VDINT1. VDINT1 will be at half 367 + * of image height 368 + */ 369 + mid_img = vert_start + (image_win->height / 2); 370 + val = (vert_start << VPFE_VDINT_VDINT0_SHIFT) | 371 + (mid_img & VPFE_VDINT_VDINT1_MASK); 372 + } 373 + 374 + vpfe_reg_write(ccdc, val, VPFE_VDINT); 375 + 376 + vpfe_reg_write(ccdc, (vert_start << VPFE_VERT_START_SLV0_SHIFT) | 377 + vert_start, VPFE_VERT_START); 378 + vpfe_reg_write(ccdc, vert_nr_lines, VPFE_VERT_LINES); 379 + } 380 + 381 + static void vpfe_reg_dump(struct vpfe_ccdc *ccdc) 382 + { 383 + struct vpfe_device *vpfe = to_vpfe(ccdc); 384 + 385 + vpfe_dbg(3, vpfe, "ALAW: 0x%x\n", vpfe_reg_read(ccdc, VPFE_ALAW)); 386 + vpfe_dbg(3, vpfe, "CLAMP: 0x%x\n", vpfe_reg_read(ccdc, VPFE_CLAMP)); 387 + vpfe_dbg(3, vpfe, "DCSUB: 0x%x\n", vpfe_reg_read(ccdc, VPFE_DCSUB)); 388 + vpfe_dbg(3, vpfe, "BLKCMP: 0x%x\n", vpfe_reg_read(ccdc, VPFE_BLKCMP)); 389 + vpfe_dbg(3, vpfe, "COLPTN: 0x%x\n", vpfe_reg_read(ccdc, VPFE_COLPTN)); 390 + vpfe_dbg(3, vpfe, "SDOFST: 0x%x\n", vpfe_reg_read(ccdc, VPFE_SDOFST)); 391 + vpfe_dbg(3, vpfe, "SYN_MODE: 0x%x\n", 392 + vpfe_reg_read(ccdc, VPFE_SYNMODE)); 393 + vpfe_dbg(3, vpfe, "HSIZE_OFF: 0x%x\n", 394 + vpfe_reg_read(ccdc, VPFE_HSIZE_OFF)); 395 + vpfe_dbg(3, vpfe, "HORZ_INFO: 0x%x\n", 396 + vpfe_reg_read(ccdc, VPFE_HORZ_INFO)); 397 + vpfe_dbg(3, vpfe, "VERT_START: 0x%x\n", 398 + vpfe_reg_read(ccdc, VPFE_VERT_START)); 399 + vpfe_dbg(3, vpfe, "VERT_LINES: 0x%x\n", 400 + vpfe_reg_read(ccdc, VPFE_VERT_LINES)); 401 + } 402 + 403 + static int 404 + vpfe_ccdc_validate_param(struct vpfe_ccdc *ccdc, 405 + struct vpfe_ccdc_config_params_raw *ccdcparam) 406 + { 407 + struct vpfe_device *vpfe = to_vpfe(ccdc); 408 + u8 max_gamma, max_data; 409 + 410 + if (!ccdcparam->alaw.enable) 411 + return 0; 412 + 413 + max_gamma = ccdc_gamma_width_max_bit(ccdcparam->alaw.gamma_wd); 414 + max_data = ccdc_data_size_max_bit(ccdcparam->data_sz); 415 + 416 + if (ccdcparam->alaw.gamma_wd > VPFE_CCDC_GAMMA_BITS_09_0 || 417 + ccdcparam->alaw.gamma_wd < VPFE_CCDC_GAMMA_BITS_15_6 || 418 + max_gamma > max_data) { 419 + vpfe_dbg(1, vpfe, "Invalid data line select\n"); 420 + return -EINVAL; 421 + } 422 + 423 + return 0; 424 + } 425 + 426 + static void 427 + vpfe_ccdc_update_raw_params(struct vpfe_ccdc *ccdc, 428 + struct vpfe_ccdc_config_params_raw *raw_params) 429 + { 430 + struct vpfe_ccdc_config_params_raw *config_params = 431 + &ccdc->ccdc_cfg.bayer.config_params; 432 + 433 + config_params = raw_params; 434 + } 435 + 436 + /* 437 + * vpfe_ccdc_restore_defaults() 438 + * This function will write defaults to all CCDC registers 439 + */ 440 + static void vpfe_ccdc_restore_defaults(struct vpfe_ccdc *ccdc) 441 + { 442 + int i; 443 + 444 + /* Disable CCDC */ 445 + vpfe_pcr_enable(ccdc, 0); 446 + 447 + /* set all registers to default value */ 448 + for (i = 4; i <= 0x94; i += 4) 449 + vpfe_reg_write(ccdc, 0, i); 450 + 451 + vpfe_reg_write(ccdc, VPFE_NO_CULLING, VPFE_CULLING); 452 + vpfe_reg_write(ccdc, VPFE_CCDC_GAMMA_BITS_11_2, VPFE_ALAW); 453 + } 454 + 455 + static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev) 456 + { 457 + int dma_cntl, i, pcr; 458 + 459 + /* If the CCDC module is still busy wait for it to be done */ 460 + for (i = 0; i < 10; i++) { 461 + usleep_range(5000, 6000); 462 + pcr = vpfe_reg_read(ccdc, VPFE_PCR); 463 + if (!pcr) 464 + break; 465 + 466 + /* make sure it it is disabled */ 467 + vpfe_pcr_enable(ccdc, 0); 468 + } 469 + 470 + /* Disable CCDC by resetting all register to default POR values */ 471 + vpfe_ccdc_restore_defaults(ccdc); 472 + 473 + /* if DMA_CNTL overflow bit is set. Clear it 474 + * It appears to take a while for this to become quiescent ~20ms 475 + */ 476 + for (i = 0; i < 10; i++) { 477 + dma_cntl = vpfe_reg_read(ccdc, VPFE_DMA_CNTL); 478 + if (!(dma_cntl & VPFE_DMA_CNTL_OVERFLOW)) 479 + break; 480 + 481 + /* Clear the overflow bit */ 482 + vpfe_reg_write(ccdc, dma_cntl, VPFE_DMA_CNTL); 483 + usleep_range(5000, 6000); 484 + } 485 + 486 + /* Disabled the module at the CONFIG level */ 487 + vpfe_config_enable(ccdc, 0); 488 + 489 + pm_runtime_put_sync(dev); 490 + 491 + return 0; 492 + } 493 + 494 + static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params) 495 + { 496 + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); 497 + struct vpfe_ccdc_config_params_raw raw_params; 498 + int x; 499 + 500 + if (ccdc->ccdc_cfg.if_type != VPFE_RAW_BAYER) 501 + return -EINVAL; 502 + 503 + x = copy_from_user(&raw_params, params, sizeof(raw_params)); 504 + if (x) { 505 + vpfe_dbg(1, vpfe, 506 + "vpfe_ccdc_set_params: error in copying ccdc params, %d\n", 507 + x); 508 + return -EFAULT; 509 + } 510 + 511 + if (!vpfe_ccdc_validate_param(ccdc, &raw_params)) { 512 + vpfe_ccdc_update_raw_params(ccdc, &raw_params); 513 + return 0; 514 + } 515 + 516 + return -EINVAL; 517 + } 518 + 519 + /* 520 + * vpfe_ccdc_config_ycbcr() 521 + * This function will configure CCDC for YCbCr video capture 522 + */ 523 + static void vpfe_ccdc_config_ycbcr(struct vpfe_ccdc *ccdc) 524 + { 525 + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); 526 + struct ccdc_params_ycbcr *params = &ccdc->ccdc_cfg.ycbcr; 527 + u32 syn_mode; 528 + 529 + vpfe_dbg(3, vpfe, "vpfe_ccdc_config_ycbcr:\n"); 530 + /* 531 + * first restore the CCDC registers to default values 532 + * This is important since we assume default values to be set in 533 + * a lot of registers that we didn't touch 534 + */ 535 + vpfe_ccdc_restore_defaults(ccdc); 536 + 537 + /* 538 + * configure pixel format, frame format, configure video frame 539 + * format, enable output to SDRAM, enable internal timing generator 540 + * and 8bit pack mode 541 + */ 542 + syn_mode = (((params->pix_fmt & VPFE_SYN_MODE_INPMOD_MASK) << 543 + VPFE_SYN_MODE_INPMOD_SHIFT) | 544 + ((params->frm_fmt & VPFE_SYN_FLDMODE_MASK) << 545 + VPFE_SYN_FLDMODE_SHIFT) | VPFE_VDHDEN_ENABLE | 546 + VPFE_WEN_ENABLE | VPFE_DATA_PACK_ENABLE); 547 + 548 + /* setup BT.656 sync mode */ 549 + if (params->bt656_enable) { 550 + vpfe_reg_write(ccdc, VPFE_REC656IF_BT656_EN, VPFE_REC656IF); 551 + 552 + /* 553 + * configure the FID, VD, HD pin polarity, 554 + * fld,hd pol positive, vd negative, 8-bit data 555 + */ 556 + syn_mode |= VPFE_SYN_MODE_VD_POL_NEGATIVE; 557 + if (ccdc->ccdc_cfg.if_type == VPFE_BT656_10BIT) 558 + syn_mode |= VPFE_SYN_MODE_10BITS; 559 + else 560 + syn_mode |= VPFE_SYN_MODE_8BITS; 561 + } else { 562 + /* y/c external sync mode */ 563 + syn_mode |= (((params->fid_pol & VPFE_FID_POL_MASK) << 564 + VPFE_FID_POL_SHIFT) | 565 + ((params->hd_pol & VPFE_HD_POL_MASK) << 566 + VPFE_HD_POL_SHIFT) | 567 + ((params->vd_pol & VPFE_VD_POL_MASK) << 568 + VPFE_VD_POL_SHIFT)); 569 + } 570 + vpfe_reg_write(ccdc, syn_mode, VPFE_SYNMODE); 571 + 572 + /* configure video window */ 573 + vpfe_ccdc_setwin(ccdc, &params->win, 574 + params->frm_fmt, params->bytesperpixel); 575 + 576 + /* 577 + * configure the order of y cb cr in SDRAM, and disable latch 578 + * internal register on vsync 579 + */ 580 + if (ccdc->ccdc_cfg.if_type == VPFE_BT656_10BIT) 581 + vpfe_reg_write(ccdc, 582 + (params->pix_order << VPFE_CCDCFG_Y8POS_SHIFT) | 583 + VPFE_LATCH_ON_VSYNC_DISABLE | 584 + VPFE_CCDCFG_BW656_10BIT, VPFE_CCDCFG); 585 + else 586 + vpfe_reg_write(ccdc, 587 + (params->pix_order << VPFE_CCDCFG_Y8POS_SHIFT) | 588 + VPFE_LATCH_ON_VSYNC_DISABLE, VPFE_CCDCFG); 589 + 590 + /* 591 + * configure the horizontal line offset. This should be a 592 + * on 32 byte boundary. So clear LSB 5 bits 593 + */ 594 + vpfe_reg_write(ccdc, params->bytesperline, VPFE_HSIZE_OFF); 595 + 596 + /* configure the memory line offset */ 597 + if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) 598 + /* two fields are interleaved in memory */ 599 + vpfe_reg_write(ccdc, VPFE_SDOFST_FIELD_INTERLEAVED, 600 + VPFE_SDOFST); 601 + } 602 + 603 + static void 604 + vpfe_ccdc_config_black_clamp(struct vpfe_ccdc *ccdc, 605 + struct vpfe_ccdc_black_clamp *bclamp) 606 + { 607 + u32 val; 608 + 609 + if (!bclamp->enable) { 610 + /* configure DCSub */ 611 + val = (bclamp->dc_sub) & VPFE_BLK_DC_SUB_MASK; 612 + vpfe_reg_write(ccdc, val, VPFE_DCSUB); 613 + vpfe_reg_write(ccdc, VPFE_CLAMP_DEFAULT_VAL, VPFE_CLAMP); 614 + return; 615 + } 616 + /* 617 + * Configure gain, Start pixel, No of line to be avg, 618 + * No of pixel/line to be avg, & Enable the Black clamping 619 + */ 620 + val = ((bclamp->sgain & VPFE_BLK_SGAIN_MASK) | 621 + ((bclamp->start_pixel & VPFE_BLK_ST_PXL_MASK) << 622 + VPFE_BLK_ST_PXL_SHIFT) | 623 + ((bclamp->sample_ln & VPFE_BLK_SAMPLE_LINE_MASK) << 624 + VPFE_BLK_SAMPLE_LINE_SHIFT) | 625 + ((bclamp->sample_pixel & VPFE_BLK_SAMPLE_LN_MASK) << 626 + VPFE_BLK_SAMPLE_LN_SHIFT) | VPFE_BLK_CLAMP_ENABLE); 627 + vpfe_reg_write(ccdc, val, VPFE_CLAMP); 628 + /* If Black clamping is enable then make dcsub 0 */ 629 + vpfe_reg_write(ccdc, VPFE_DCSUB_DEFAULT_VAL, VPFE_DCSUB); 630 + } 631 + 632 + static void 633 + vpfe_ccdc_config_black_compense(struct vpfe_ccdc *ccdc, 634 + struct vpfe_ccdc_black_compensation *bcomp) 635 + { 636 + u32 val; 637 + 638 + val = ((bcomp->b & VPFE_BLK_COMP_MASK) | 639 + ((bcomp->gb & VPFE_BLK_COMP_MASK) << 640 + VPFE_BLK_COMP_GB_COMP_SHIFT) | 641 + ((bcomp->gr & VPFE_BLK_COMP_MASK) << 642 + VPFE_BLK_COMP_GR_COMP_SHIFT) | 643 + ((bcomp->r & VPFE_BLK_COMP_MASK) << 644 + VPFE_BLK_COMP_R_COMP_SHIFT)); 645 + vpfe_reg_write(ccdc, val, VPFE_BLKCMP); 646 + } 647 + 648 + /* 649 + * vpfe_ccdc_config_raw() 650 + * This function will configure CCDC for Raw capture mode 651 + */ 652 + static void vpfe_ccdc_config_raw(struct vpfe_ccdc *ccdc) 653 + { 654 + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); 655 + struct vpfe_ccdc_config_params_raw *config_params = 656 + &ccdc->ccdc_cfg.bayer.config_params; 657 + struct ccdc_params_raw *params = &ccdc->ccdc_cfg.bayer; 658 + unsigned int syn_mode; 659 + unsigned int val; 660 + 661 + vpfe_dbg(3, vpfe, "vpfe_ccdc_config_raw:\n"); 662 + 663 + /* Reset CCDC */ 664 + vpfe_ccdc_restore_defaults(ccdc); 665 + 666 + /* Disable latching function registers on VSYNC */ 667 + vpfe_reg_write(ccdc, VPFE_LATCH_ON_VSYNC_DISABLE, VPFE_CCDCFG); 668 + 669 + /* 670 + * Configure the vertical sync polarity(SYN_MODE.VDPOL), 671 + * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity 672 + * (SYN_MODE.FLDPOL), frame format(progressive or interlace), 673 + * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output 674 + * SDRAM, enable internal timing generator 675 + */ 676 + syn_mode = (((params->vd_pol & VPFE_VD_POL_MASK) << VPFE_VD_POL_SHIFT) | 677 + ((params->hd_pol & VPFE_HD_POL_MASK) << VPFE_HD_POL_SHIFT) | 678 + ((params->fid_pol & VPFE_FID_POL_MASK) << 679 + VPFE_FID_POL_SHIFT) | ((params->frm_fmt & 680 + VPFE_FRM_FMT_MASK) << VPFE_FRM_FMT_SHIFT) | 681 + ((config_params->data_sz & VPFE_DATA_SZ_MASK) << 682 + VPFE_DATA_SZ_SHIFT) | ((params->pix_fmt & 683 + VPFE_PIX_FMT_MASK) << VPFE_PIX_FMT_SHIFT) | 684 + VPFE_WEN_ENABLE | VPFE_VDHDEN_ENABLE); 685 + 686 + /* Enable and configure aLaw register if needed */ 687 + if (config_params->alaw.enable) { 688 + val = ((config_params->alaw.gamma_wd & 689 + VPFE_ALAW_GAMMA_WD_MASK) | VPFE_ALAW_ENABLE); 690 + vpfe_reg_write(ccdc, val, VPFE_ALAW); 691 + vpfe_dbg(3, vpfe, "\nWriting 0x%x to ALAW...\n", val); 692 + } 693 + 694 + /* Configure video window */ 695 + vpfe_ccdc_setwin(ccdc, &params->win, params->frm_fmt, 696 + params->bytesperpixel); 697 + 698 + /* Configure Black Clamp */ 699 + vpfe_ccdc_config_black_clamp(ccdc, &config_params->blk_clamp); 700 + 701 + /* Configure Black level compensation */ 702 + vpfe_ccdc_config_black_compense(ccdc, &config_params->blk_comp); 703 + 704 + /* If data size is 8 bit then pack the data */ 705 + if ((config_params->data_sz == VPFE_CCDC_DATA_8BITS) || 706 + config_params->alaw.enable) 707 + syn_mode |= VPFE_DATA_PACK_ENABLE; 708 + 709 + /* 710 + * Configure Horizontal offset register. If pack 8 is enabled then 711 + * 1 pixel will take 1 byte 712 + */ 713 + vpfe_reg_write(ccdc, params->bytesperline, VPFE_HSIZE_OFF); 714 + 715 + vpfe_dbg(3, vpfe, "Writing %d (%x) to HSIZE_OFF\n", 716 + params->bytesperline, params->bytesperline); 717 + 718 + /* Set value for SDOFST */ 719 + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { 720 + if (params->image_invert_enable) { 721 + /* For interlace inverse mode */ 722 + vpfe_reg_write(ccdc, VPFE_INTERLACED_IMAGE_INVERT, 723 + VPFE_SDOFST); 724 + } else { 725 + /* For interlace non inverse mode */ 726 + vpfe_reg_write(ccdc, VPFE_INTERLACED_NO_IMAGE_INVERT, 727 + VPFE_SDOFST); 728 + } 729 + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { 730 + vpfe_reg_write(ccdc, VPFE_PROGRESSIVE_NO_IMAGE_INVERT, 731 + VPFE_SDOFST); 732 + } 733 + 734 + vpfe_reg_write(ccdc, syn_mode, VPFE_SYNMODE); 735 + 736 + vpfe_reg_dump(ccdc); 737 + } 738 + 739 + static inline int 740 + vpfe_ccdc_set_buftype(struct vpfe_ccdc *ccdc, 741 + enum ccdc_buftype buf_type) 742 + { 743 + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) 744 + ccdc->ccdc_cfg.bayer.buf_type = buf_type; 745 + else 746 + ccdc->ccdc_cfg.ycbcr.buf_type = buf_type; 747 + 748 + return 0; 749 + } 750 + 751 + static inline enum ccdc_buftype vpfe_ccdc_get_buftype(struct vpfe_ccdc *ccdc) 752 + { 753 + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) 754 + return ccdc->ccdc_cfg.bayer.buf_type; 755 + 756 + return ccdc->ccdc_cfg.ycbcr.buf_type; 757 + } 758 + 759 + static int vpfe_ccdc_set_pixel_format(struct vpfe_ccdc *ccdc, u32 pixfmt) 760 + { 761 + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); 762 + 763 + vpfe_dbg(1, vpfe, "vpfe_ccdc_set_pixel_format: if_type: %d, pixfmt:%s\n", 764 + ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt)); 765 + 766 + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { 767 + ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; 768 + /* 769 + * Need to clear it in case it was left on 770 + * after the last capture. 771 + */ 772 + ccdc->ccdc_cfg.bayer.config_params.alaw.enable = 0; 773 + 774 + switch (pixfmt) { 775 + case V4L2_PIX_FMT_SBGGR8: 776 + ccdc->ccdc_cfg.bayer.config_params.alaw.enable = 1; 777 + break; 778 + 779 + case V4L2_PIX_FMT_YUYV: 780 + case V4L2_PIX_FMT_UYVY: 781 + case V4L2_PIX_FMT_YUV420: 782 + case V4L2_PIX_FMT_NV12: 783 + case V4L2_PIX_FMT_RGB565X: 784 + break; 785 + 786 + case V4L2_PIX_FMT_SBGGR16: 787 + default: 788 + return -EINVAL; 789 + } 790 + } else { 791 + switch (pixfmt) { 792 + case V4L2_PIX_FMT_YUYV: 793 + ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; 794 + break; 795 + 796 + case V4L2_PIX_FMT_UYVY: 797 + ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; 798 + break; 799 + 800 + default: 801 + return -EINVAL; 802 + } 803 + } 804 + 805 + return 0; 806 + } 807 + 808 + static u32 vpfe_ccdc_get_pixel_format(struct vpfe_ccdc *ccdc) 809 + { 810 + u32 pixfmt; 811 + 812 + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { 813 + pixfmt = V4L2_PIX_FMT_YUYV; 814 + } else { 815 + if (ccdc->ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) 816 + pixfmt = V4L2_PIX_FMT_YUYV; 817 + else 818 + pixfmt = V4L2_PIX_FMT_UYVY; 819 + } 820 + 821 + return pixfmt; 822 + } 823 + 824 + static int 825 + vpfe_ccdc_set_image_window(struct vpfe_ccdc *ccdc, 826 + struct v4l2_rect *win, unsigned int bpp) 827 + { 828 + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { 829 + ccdc->ccdc_cfg.bayer.win = *win; 830 + ccdc->ccdc_cfg.bayer.bytesperpixel = bpp; 831 + ccdc->ccdc_cfg.bayer.bytesperline = ALIGN(win->width * bpp, 32); 832 + } else { 833 + ccdc->ccdc_cfg.ycbcr.win = *win; 834 + ccdc->ccdc_cfg.ycbcr.bytesperpixel = bpp; 835 + ccdc->ccdc_cfg.ycbcr.bytesperline = ALIGN(win->width * bpp, 32); 836 + } 837 + 838 + return 0; 839 + } 840 + 841 + static inline void 842 + vpfe_ccdc_get_image_window(struct vpfe_ccdc *ccdc, 843 + struct v4l2_rect *win) 844 + { 845 + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) 846 + *win = ccdc->ccdc_cfg.bayer.win; 847 + else 848 + *win = ccdc->ccdc_cfg.ycbcr.win; 849 + } 850 + 851 + static inline unsigned int vpfe_ccdc_get_line_length(struct vpfe_ccdc *ccdc) 852 + { 853 + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) 854 + return ccdc->ccdc_cfg.bayer.bytesperline; 855 + 856 + return ccdc->ccdc_cfg.ycbcr.bytesperline; 857 + } 858 + 859 + static inline int 860 + vpfe_ccdc_set_frame_format(struct vpfe_ccdc *ccdc, 861 + enum ccdc_frmfmt frm_fmt) 862 + { 863 + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) 864 + ccdc->ccdc_cfg.bayer.frm_fmt = frm_fmt; 865 + else 866 + ccdc->ccdc_cfg.ycbcr.frm_fmt = frm_fmt; 867 + 868 + return 0; 869 + } 870 + 871 + static inline enum ccdc_frmfmt 872 + vpfe_ccdc_get_frame_format(struct vpfe_ccdc *ccdc) 873 + { 874 + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) 875 + return ccdc->ccdc_cfg.bayer.frm_fmt; 876 + 877 + return ccdc->ccdc_cfg.ycbcr.frm_fmt; 878 + } 879 + 880 + static inline int vpfe_ccdc_getfid(struct vpfe_ccdc *ccdc) 881 + { 882 + return (vpfe_reg_read(ccdc, VPFE_SYNMODE) >> 15) & 1; 883 + } 884 + 885 + static inline void vpfe_set_sdr_addr(struct vpfe_ccdc *ccdc, unsigned long addr) 886 + { 887 + vpfe_reg_write(ccdc, addr & 0xffffffe0, VPFE_SDR_ADDR); 888 + } 889 + 890 + static int vpfe_ccdc_set_hw_if_params(struct vpfe_ccdc *ccdc, 891 + struct vpfe_hw_if_param *params) 892 + { 893 + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); 894 + 895 + ccdc->ccdc_cfg.if_type = params->if_type; 896 + 897 + switch (params->if_type) { 898 + case VPFE_BT656: 899 + case VPFE_YCBCR_SYNC_16: 900 + case VPFE_YCBCR_SYNC_8: 901 + case VPFE_BT656_10BIT: 902 + ccdc->ccdc_cfg.ycbcr.vd_pol = params->vdpol; 903 + ccdc->ccdc_cfg.ycbcr.hd_pol = params->hdpol; 904 + break; 905 + 906 + case VPFE_RAW_BAYER: 907 + ccdc->ccdc_cfg.bayer.vd_pol = params->vdpol; 908 + ccdc->ccdc_cfg.bayer.hd_pol = params->hdpol; 909 + if (params->bus_width == 10) 910 + ccdc->ccdc_cfg.bayer.config_params.data_sz = 911 + VPFE_CCDC_DATA_10BITS; 912 + else 913 + ccdc->ccdc_cfg.bayer.config_params.data_sz = 914 + VPFE_CCDC_DATA_8BITS; 915 + vpfe_dbg(1, vpfe, "params.bus_width: %d\n", 916 + params->bus_width); 917 + vpfe_dbg(1, vpfe, "config_params.data_sz: %d\n", 918 + ccdc->ccdc_cfg.bayer.config_params.data_sz); 919 + break; 920 + 921 + default: 922 + return -EINVAL; 923 + } 924 + 925 + return 0; 926 + } 927 + 928 + static void vpfe_clear_intr(struct vpfe_ccdc *ccdc, int vdint) 929 + { 930 + unsigned int vpfe_int_status; 931 + 932 + vpfe_int_status = vpfe_reg_read(ccdc, VPFE_IRQ_STS); 933 + 934 + switch (vdint) { 935 + /* VD0 interrupt */ 936 + case VPFE_VDINT0: 937 + vpfe_int_status &= ~VPFE_VDINT0; 938 + vpfe_int_status |= VPFE_VDINT0; 939 + break; 940 + 941 + /* VD1 interrupt */ 942 + case VPFE_VDINT1: 943 + vpfe_int_status &= ~VPFE_VDINT1; 944 + vpfe_int_status |= VPFE_VDINT1; 945 + break; 946 + 947 + /* VD2 interrupt */ 948 + case VPFE_VDINT2: 949 + vpfe_int_status &= ~VPFE_VDINT2; 950 + vpfe_int_status |= VPFE_VDINT2; 951 + break; 952 + 953 + /* Clear all interrupts */ 954 + default: 955 + vpfe_int_status &= ~(VPFE_VDINT0 | 956 + VPFE_VDINT1 | 957 + VPFE_VDINT2); 958 + vpfe_int_status |= (VPFE_VDINT0 | 959 + VPFE_VDINT1 | 960 + VPFE_VDINT2); 961 + break; 962 + } 963 + /* Clear specific VDINT from the status register */ 964 + vpfe_reg_write(ccdc, vpfe_int_status, VPFE_IRQ_STS); 965 + 966 + vpfe_int_status = vpfe_reg_read(ccdc, VPFE_IRQ_STS); 967 + 968 + /* Acknowledge that we are done with all interrupts */ 969 + vpfe_reg_write(ccdc, 1, VPFE_IRQ_EOI); 970 + } 971 + 972 + static void vpfe_ccdc_config_defaults(struct vpfe_ccdc *ccdc) 973 + { 974 + ccdc->ccdc_cfg.if_type = VPFE_RAW_BAYER; 975 + 976 + ccdc->ccdc_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; 977 + ccdc->ccdc_cfg.ycbcr.frm_fmt = CCDC_FRMFMT_INTERLACED; 978 + ccdc->ccdc_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE; 979 + ccdc->ccdc_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE; 980 + ccdc->ccdc_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE; 981 + ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; 982 + ccdc->ccdc_cfg.ycbcr.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED; 983 + 984 + ccdc->ccdc_cfg.ycbcr.win.left = 0; 985 + ccdc->ccdc_cfg.ycbcr.win.top = 0; 986 + ccdc->ccdc_cfg.ycbcr.win.width = 720; 987 + ccdc->ccdc_cfg.ycbcr.win.height = 576; 988 + ccdc->ccdc_cfg.ycbcr.bt656_enable = 1; 989 + 990 + ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; 991 + ccdc->ccdc_cfg.bayer.frm_fmt = CCDC_FRMFMT_PROGRESSIVE; 992 + ccdc->ccdc_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE; 993 + ccdc->ccdc_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE; 994 + ccdc->ccdc_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE; 995 + 996 + ccdc->ccdc_cfg.bayer.win.left = 0; 997 + ccdc->ccdc_cfg.bayer.win.top = 0; 998 + ccdc->ccdc_cfg.bayer.win.width = 800; 999 + ccdc->ccdc_cfg.bayer.win.height = 600; 1000 + ccdc->ccdc_cfg.bayer.config_params.data_sz = VPFE_CCDC_DATA_8BITS; 1001 + ccdc->ccdc_cfg.bayer.config_params.alaw.gamma_wd = 1002 + VPFE_CCDC_GAMMA_BITS_09_0; 1003 + } 1004 + 1005 + /* 1006 + * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings 1007 + */ 1008 + static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe, 1009 + struct v4l2_format *f) 1010 + { 1011 + struct v4l2_rect image_win; 1012 + enum ccdc_buftype buf_type; 1013 + enum ccdc_frmfmt frm_fmt; 1014 + 1015 + memset(f, 0, sizeof(*f)); 1016 + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1017 + vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win); 1018 + f->fmt.pix.width = image_win.width; 1019 + f->fmt.pix.height = image_win.height; 1020 + f->fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc); 1021 + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * 1022 + f->fmt.pix.height; 1023 + buf_type = vpfe_ccdc_get_buftype(&vpfe->ccdc); 1024 + f->fmt.pix.pixelformat = vpfe_ccdc_get_pixel_format(&vpfe->ccdc); 1025 + frm_fmt = vpfe_ccdc_get_frame_format(&vpfe->ccdc); 1026 + 1027 + if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { 1028 + f->fmt.pix.field = V4L2_FIELD_NONE; 1029 + } else if (frm_fmt == CCDC_FRMFMT_INTERLACED) { 1030 + if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { 1031 + f->fmt.pix.field = V4L2_FIELD_INTERLACED; 1032 + } else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED) { 1033 + f->fmt.pix.field = V4L2_FIELD_SEQ_TB; 1034 + } else { 1035 + vpfe_err(vpfe, "Invalid buf_type\n"); 1036 + return -EINVAL; 1037 + } 1038 + } else { 1039 + vpfe_err(vpfe, "Invalid frm_fmt\n"); 1040 + return -EINVAL; 1041 + } 1042 + return 0; 1043 + } 1044 + 1045 + static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) 1046 + { 1047 + enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; 1048 + int ret; 1049 + 1050 + vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n"); 1051 + 1052 + vpfe_dbg(1, vpfe, "pixelformat: %s\n", 1053 + print_fourcc(vpfe->fmt.fmt.pix.pixelformat)); 1054 + 1055 + if (vpfe_ccdc_set_pixel_format(&vpfe->ccdc, 1056 + vpfe->fmt.fmt.pix.pixelformat) < 0) { 1057 + vpfe_err(vpfe, "couldn't set pix format in ccdc\n"); 1058 + return -EINVAL; 1059 + } 1060 + 1061 + /* configure the image window */ 1062 + vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, vpfe->bpp); 1063 + 1064 + switch (vpfe->fmt.fmt.pix.field) { 1065 + case V4L2_FIELD_INTERLACED: 1066 + /* do nothing, since it is default */ 1067 + ret = vpfe_ccdc_set_buftype( 1068 + &vpfe->ccdc, 1069 + CCDC_BUFTYPE_FLD_INTERLEAVED); 1070 + break; 1071 + 1072 + case V4L2_FIELD_NONE: 1073 + frm_fmt = CCDC_FRMFMT_PROGRESSIVE; 1074 + /* buffer type only applicable for interlaced scan */ 1075 + break; 1076 + 1077 + case V4L2_FIELD_SEQ_TB: 1078 + ret = vpfe_ccdc_set_buftype( 1079 + &vpfe->ccdc, 1080 + CCDC_BUFTYPE_FLD_SEPARATED); 1081 + break; 1082 + 1083 + default: 1084 + return -EINVAL; 1085 + } 1086 + 1087 + if (ret) 1088 + return ret; 1089 + 1090 + return vpfe_ccdc_set_frame_format(&vpfe->ccdc, frm_fmt); 1091 + } 1092 + 1093 + /* 1094 + * vpfe_config_image_format() 1095 + * For a given standard, this functions sets up the default 1096 + * pix format & crop values in the vpfe device and ccdc. It first 1097 + * starts with defaults based values from the standard table. 1098 + * It then checks if sub device support g_mbus_fmt and then override the 1099 + * values based on that.Sets crop values to match with scan resolution 1100 + * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the 1101 + * values in ccdc 1102 + */ 1103 + static int vpfe_config_image_format(struct vpfe_device *vpfe, 1104 + v4l2_std_id std_id) 1105 + { 1106 + struct v4l2_pix_format *pix = &vpfe->fmt.fmt.pix; 1107 + int i, ret; 1108 + 1109 + for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { 1110 + if (vpfe_standards[i].std_id & std_id) { 1111 + vpfe->std_info.active_pixels = 1112 + vpfe_standards[i].width; 1113 + vpfe->std_info.active_lines = 1114 + vpfe_standards[i].height; 1115 + vpfe->std_info.frame_format = 1116 + vpfe_standards[i].frame_format; 1117 + vpfe->std_index = i; 1118 + 1119 + break; 1120 + } 1121 + } 1122 + 1123 + if (i == ARRAY_SIZE(vpfe_standards)) { 1124 + vpfe_err(vpfe, "standard not supported\n"); 1125 + return -EINVAL; 1126 + } 1127 + 1128 + vpfe->crop.top = vpfe->crop.left = 0; 1129 + vpfe->crop.width = vpfe->std_info.active_pixels; 1130 + vpfe->crop.height = vpfe->std_info.active_lines; 1131 + pix->width = vpfe->crop.width; 1132 + pix->height = vpfe->crop.height; 1133 + pix->pixelformat = V4L2_PIX_FMT_YUYV; 1134 + 1135 + /* first field and frame format based on standard frame format */ 1136 + if (vpfe->std_info.frame_format) 1137 + pix->field = V4L2_FIELD_INTERLACED; 1138 + else 1139 + pix->field = V4L2_FIELD_NONE; 1140 + 1141 + ret = __vpfe_get_format(vpfe, &vpfe->fmt, &vpfe->bpp); 1142 + if (ret) 1143 + return ret; 1144 + 1145 + /* Update the crop window based on found values */ 1146 + vpfe->crop.width = pix->width; 1147 + vpfe->crop.height = pix->height; 1148 + 1149 + return vpfe_config_ccdc_image_format(vpfe); 1150 + } 1151 + 1152 + static int vpfe_initialize_device(struct vpfe_device *vpfe) 1153 + { 1154 + struct vpfe_subdev_info *sdinfo; 1155 + int ret; 1156 + 1157 + sdinfo = &vpfe->cfg->sub_devs[0]; 1158 + sdinfo->sd = vpfe->sd[0]; 1159 + vpfe->current_input = 0; 1160 + vpfe->std_index = 0; 1161 + /* Configure the default format information */ 1162 + ret = vpfe_config_image_format(vpfe, 1163 + vpfe_standards[vpfe->std_index].std_id); 1164 + if (ret) 1165 + return ret; 1166 + 1167 + pm_runtime_get_sync(vpfe->pdev); 1168 + 1169 + vpfe_config_enable(&vpfe->ccdc, 1); 1170 + 1171 + vpfe_ccdc_restore_defaults(&vpfe->ccdc); 1172 + 1173 + /* Clear all VPFE interrupts */ 1174 + vpfe_clear_intr(&vpfe->ccdc, -1); 1175 + 1176 + return ret; 1177 + } 1178 + 1179 + /* 1180 + * vpfe_release : This function is based on the vb2_fop_release 1181 + * helper function. 1182 + * It has been augmented to handle module power management, 1183 + * by disabling/enabling h/w module fcntl clock when necessary. 1184 + */ 1185 + static int vpfe_release(struct file *file) 1186 + { 1187 + struct vpfe_device *vpfe = video_drvdata(file); 1188 + int ret; 1189 + 1190 + mutex_lock(&vpfe->lock); 1191 + 1192 + if (v4l2_fh_is_singular_file(file)) 1193 + vpfe_ccdc_close(&vpfe->ccdc, vpfe->pdev); 1194 + ret = _vb2_fop_release(file, NULL); 1195 + 1196 + mutex_unlock(&vpfe->lock); 1197 + 1198 + return ret; 1199 + } 1200 + 1201 + /* 1202 + * vpfe_open : This function is based on the v4l2_fh_open helper function. 1203 + * It has been augmented to handle module power management, 1204 + * by disabling/enabling h/w module fcntl clock when necessary. 1205 + */ 1206 + static int vpfe_open(struct file *file) 1207 + { 1208 + struct vpfe_device *vpfe = video_drvdata(file); 1209 + int ret; 1210 + 1211 + mutex_lock(&vpfe->lock); 1212 + 1213 + ret = v4l2_fh_open(file); 1214 + if (ret) { 1215 + vpfe_err(vpfe, "v4l2_fh_open failed\n"); 1216 + goto unlock; 1217 + } 1218 + 1219 + if (!v4l2_fh_is_singular_file(file)) 1220 + goto unlock; 1221 + 1222 + if (vpfe_initialize_device(vpfe)) { 1223 + v4l2_fh_release(file); 1224 + ret = -ENODEV; 1225 + } 1226 + 1227 + unlock: 1228 + mutex_unlock(&vpfe->lock); 1229 + return ret; 1230 + } 1231 + 1232 + /** 1233 + * vpfe_schedule_next_buffer: set next buffer address for capture 1234 + * @vpfe : ptr to vpfe device 1235 + * 1236 + * This function will get next buffer from the dma queue and 1237 + * set the buffer address in the vpfe register for capture. 1238 + * the buffer is marked active 1239 + * 1240 + * Assumes caller is holding vpfe->dma_queue_lock already 1241 + */ 1242 + static inline void vpfe_schedule_next_buffer(struct vpfe_device *vpfe) 1243 + { 1244 + vpfe->next_frm = list_entry(vpfe->dma_queue.next, 1245 + struct vpfe_cap_buffer, list); 1246 + list_del(&vpfe->next_frm->list); 1247 + 1248 + vpfe_set_sdr_addr(&vpfe->ccdc, 1249 + vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb, 0)); 1250 + } 1251 + 1252 + static inline void vpfe_schedule_bottom_field(struct vpfe_device *vpfe) 1253 + { 1254 + unsigned long addr; 1255 + 1256 + addr = vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb, 0) + 1257 + vpfe->field_off; 1258 + 1259 + vpfe_set_sdr_addr(&vpfe->ccdc, addr); 1260 + } 1261 + 1262 + /* 1263 + * vpfe_process_buffer_complete: process a completed buffer 1264 + * @vpfe : ptr to vpfe device 1265 + * 1266 + * This function time stamp the buffer and mark it as DONE. It also 1267 + * wake up any process waiting on the QUEUE and set the next buffer 1268 + * as current 1269 + */ 1270 + static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe) 1271 + { 1272 + v4l2_get_timestamp(&vpfe->cur_frm->vb.v4l2_buf.timestamp); 1273 + vpfe->cur_frm->vb.v4l2_buf.field = vpfe->fmt.fmt.pix.field; 1274 + vpfe->cur_frm->vb.v4l2_buf.sequence = vpfe->sequence++; 1275 + vb2_buffer_done(&vpfe->cur_frm->vb, VB2_BUF_STATE_DONE); 1276 + vpfe->cur_frm = vpfe->next_frm; 1277 + } 1278 + 1279 + /* 1280 + * vpfe_isr : ISR handler for vpfe capture (VINT0) 1281 + * @irq: irq number 1282 + * @dev_id: dev_id ptr 1283 + * 1284 + * It changes status of the captured buffer, takes next buffer from the queue 1285 + * and sets its address in VPFE registers 1286 + */ 1287 + static irqreturn_t vpfe_isr(int irq, void *dev) 1288 + { 1289 + struct vpfe_device *vpfe = (struct vpfe_device *)dev; 1290 + enum v4l2_field field; 1291 + int intr_status; 1292 + int fid; 1293 + 1294 + intr_status = vpfe_reg_read(&vpfe->ccdc, VPFE_IRQ_STS); 1295 + 1296 + if (intr_status & VPFE_VDINT0) { 1297 + field = vpfe->fmt.fmt.pix.field; 1298 + 1299 + if (field == V4L2_FIELD_NONE) { 1300 + /* handle progressive frame capture */ 1301 + if (vpfe->cur_frm != vpfe->next_frm) 1302 + vpfe_process_buffer_complete(vpfe); 1303 + goto next_intr; 1304 + } 1305 + 1306 + /* interlaced or TB capture check which field 1307 + we are in hardware */ 1308 + fid = vpfe_ccdc_getfid(&vpfe->ccdc); 1309 + 1310 + /* switch the software maintained field id */ 1311 + vpfe->field ^= 1; 1312 + if (fid == vpfe->field) { 1313 + /* we are in-sync here,continue */ 1314 + if (fid == 0) { 1315 + /* 1316 + * One frame is just being captured. If the 1317 + * next frame is available, release the 1318 + * current frame and move on 1319 + */ 1320 + if (vpfe->cur_frm != vpfe->next_frm) 1321 + vpfe_process_buffer_complete(vpfe); 1322 + /* 1323 + * based on whether the two fields are stored 1324 + * interleave or separately in memory, 1325 + * reconfigure the CCDC memory address 1326 + */ 1327 + if (field == V4L2_FIELD_SEQ_TB) 1328 + vpfe_schedule_bottom_field(vpfe); 1329 + 1330 + goto next_intr; 1331 + } 1332 + /* 1333 + * if one field is just being captured configure 1334 + * the next frame get the next frame from the empty 1335 + * queue if no frame is available hold on to the 1336 + * current buffer 1337 + */ 1338 + spin_lock(&vpfe->dma_queue_lock); 1339 + if (!list_empty(&vpfe->dma_queue) && 1340 + vpfe->cur_frm == vpfe->next_frm) 1341 + vpfe_schedule_next_buffer(vpfe); 1342 + spin_unlock(&vpfe->dma_queue_lock); 1343 + } else if (fid == 0) { 1344 + /* 1345 + * out of sync. Recover from any hardware out-of-sync. 1346 + * May loose one frame 1347 + */ 1348 + vpfe->field = fid; 1349 + } 1350 + } 1351 + 1352 + next_intr: 1353 + if (intr_status & VPFE_VDINT1) { 1354 + spin_lock(&vpfe->dma_queue_lock); 1355 + if (vpfe->fmt.fmt.pix.field == V4L2_FIELD_NONE && 1356 + !list_empty(&vpfe->dma_queue) && 1357 + vpfe->cur_frm == vpfe->next_frm) 1358 + vpfe_schedule_next_buffer(vpfe); 1359 + spin_unlock(&vpfe->dma_queue_lock); 1360 + } 1361 + 1362 + vpfe_clear_intr(&vpfe->ccdc, intr_status); 1363 + 1364 + return IRQ_HANDLED; 1365 + } 1366 + 1367 + static inline void vpfe_detach_irq(struct vpfe_device *vpfe) 1368 + { 1369 + unsigned int intr = VPFE_VDINT0; 1370 + enum ccdc_frmfmt frame_format; 1371 + 1372 + frame_format = vpfe_ccdc_get_frame_format(&vpfe->ccdc); 1373 + if (frame_format == CCDC_FRMFMT_PROGRESSIVE) 1374 + intr |= VPFE_VDINT1; 1375 + 1376 + vpfe_reg_write(&vpfe->ccdc, intr, VPFE_IRQ_EN_CLR); 1377 + } 1378 + 1379 + static inline void vpfe_attach_irq(struct vpfe_device *vpfe) 1380 + { 1381 + unsigned int intr = VPFE_VDINT0; 1382 + enum ccdc_frmfmt frame_format; 1383 + 1384 + frame_format = vpfe_ccdc_get_frame_format(&vpfe->ccdc); 1385 + if (frame_format == CCDC_FRMFMT_PROGRESSIVE) 1386 + intr |= VPFE_VDINT1; 1387 + 1388 + vpfe_reg_write(&vpfe->ccdc, intr, VPFE_IRQ_EN_SET); 1389 + } 1390 + 1391 + static int vpfe_querycap(struct file *file, void *priv, 1392 + struct v4l2_capability *cap) 1393 + { 1394 + struct vpfe_device *vpfe = video_drvdata(file); 1395 + 1396 + vpfe_dbg(2, vpfe, "vpfe_querycap\n"); 1397 + 1398 + strlcpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver)); 1399 + strlcpy(cap->card, "TI AM437x VPFE", sizeof(cap->card)); 1400 + snprintf(cap->bus_info, sizeof(cap->bus_info), 1401 + "platform:%s", vpfe->v4l2_dev.name); 1402 + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | 1403 + V4L2_CAP_READWRITE; 1404 + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; 1405 + 1406 + return 0; 1407 + } 1408 + 1409 + /* get the format set at output pad of the adjacent subdev */ 1410 + static int __vpfe_get_format(struct vpfe_device *vpfe, 1411 + struct v4l2_format *format, unsigned int *bpp) 1412 + { 1413 + struct v4l2_mbus_framefmt mbus_fmt; 1414 + struct vpfe_subdev_info *sdinfo; 1415 + struct v4l2_subdev_format fmt; 1416 + int ret; 1417 + 1418 + sdinfo = vpfe->current_subdev; 1419 + if (!sdinfo->sd) 1420 + return -EINVAL; 1421 + 1422 + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; 1423 + fmt.pad = 0; 1424 + 1425 + ret = v4l2_subdev_call(sdinfo->sd, pad, get_fmt, NULL, &fmt); 1426 + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) 1427 + return ret; 1428 + 1429 + if (!ret) { 1430 + v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); 1431 + mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); 1432 + } else { 1433 + ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, 1434 + sdinfo->grp_id, 1435 + video, g_mbus_fmt, 1436 + &mbus_fmt); 1437 + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) 1438 + return ret; 1439 + v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); 1440 + mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp); 1441 + } 1442 + 1443 + format->type = vpfe->fmt.type; 1444 + 1445 + vpfe_dbg(1, vpfe, 1446 + "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n", 1447 + __func__, format->fmt.pix.width, format->fmt.pix.height, 1448 + print_fourcc(format->fmt.pix.pixelformat), 1449 + format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp); 1450 + 1451 + return 0; 1452 + } 1453 + 1454 + /* set the format at output pad of the adjacent subdev */ 1455 + static int __vpfe_set_format(struct vpfe_device *vpfe, 1456 + struct v4l2_format *format, unsigned int *bpp) 1457 + { 1458 + struct v4l2_mbus_framefmt mbus_fmt; 1459 + struct vpfe_subdev_info *sdinfo; 1460 + struct v4l2_subdev_format fmt; 1461 + int ret; 1462 + 1463 + vpfe_dbg(2, vpfe, "__vpfe_set_format\n"); 1464 + 1465 + sdinfo = vpfe->current_subdev; 1466 + if (!sdinfo->sd) 1467 + return -EINVAL; 1468 + 1469 + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; 1470 + fmt.pad = 0; 1471 + 1472 + pix_to_mbus(vpfe, &format->fmt.pix, &fmt.format); 1473 + 1474 + ret = v4l2_subdev_call(sdinfo->sd, pad, set_fmt, NULL, &fmt); 1475 + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) 1476 + return ret; 1477 + 1478 + if (!ret) { 1479 + v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); 1480 + mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); 1481 + } else { 1482 + ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, 1483 + sdinfo->grp_id, 1484 + video, s_mbus_fmt, 1485 + &mbus_fmt); 1486 + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) 1487 + return ret; 1488 + 1489 + v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); 1490 + mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp); 1491 + } 1492 + 1493 + format->type = vpfe->fmt.type; 1494 + 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); 1500 + 1501 + return 0; 1502 + } 1503 + 1504 + static int vpfe_g_fmt(struct file *file, void *priv, 1505 + struct v4l2_format *fmt) 1506 + { 1507 + struct vpfe_device *vpfe = video_drvdata(file); 1508 + 1509 + vpfe_dbg(2, vpfe, "vpfe_g_fmt\n"); 1510 + 1511 + *fmt = vpfe->fmt; 1512 + 1513 + return 0; 1514 + } 1515 + 1516 + static int vpfe_enum_fmt(struct file *file, void *priv, 1517 + struct v4l2_fmtdesc *f) 1518 + { 1519 + struct vpfe_device *vpfe = video_drvdata(file); 1520 + 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); 1526 + 1527 + sdinfo = vpfe->current_subdev; 1528 + if (!sdinfo->sd) 1529 + return -EINVAL; 1530 + 1531 + if (f->index > ARRAY_SIZE(formats)) 1532 + return -EINVAL; 1533 + 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; 1542 + 1543 + strncpy(f->description, fmt->name, sizeof(f->description) - 1); 1544 + f->pixelformat = fmt->fourcc; 1545 + f->type = vpfe->fmt.type; 1546 + 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); 1549 + 1550 + return 0; 1551 + } 1552 + 1553 + static int vpfe_try_fmt(struct file *file, void *priv, 1554 + struct v4l2_format *fmt) 1555 + { 1556 + struct vpfe_device *vpfe = video_drvdata(file); 1557 + unsigned int bpp; 1558 + 1559 + vpfe_dbg(2, vpfe, "vpfe_try_fmt\n"); 1560 + 1561 + return __vpfe_get_format(vpfe, fmt, &bpp); 1562 + } 1563 + 1564 + static int vpfe_s_fmt(struct file *file, void *priv, 1565 + struct v4l2_format *fmt) 1566 + { 1567 + struct vpfe_device *vpfe = video_drvdata(file); 1568 + struct v4l2_format format; 1569 + unsigned int bpp; 1570 + int ret; 1571 + 1572 + vpfe_dbg(2, vpfe, "vpfe_s_fmt\n"); 1573 + 1574 + /* If streaming is started, return error */ 1575 + if (vb2_is_busy(&vpfe->buffer_queue)) { 1576 + vpfe_err(vpfe, "%s device busy\n", __func__); 1577 + return -EBUSY; 1578 + } 1579 + 1580 + ret = vpfe_try_fmt(file, priv, fmt); 1581 + if (ret) 1582 + return ret; 1583 + 1584 + 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; 1599 + 1600 + /* Update the crop window based on found values */ 1601 + vpfe->crop.width = fmt->fmt.pix.width; 1602 + vpfe->crop.height = fmt->fmt.pix.height; 1603 + 1604 + /* set image capture parameters in the ccdc */ 1605 + return vpfe_config_ccdc_image_format(vpfe); 1606 + } 1607 + 1608 + static int vpfe_enum_size(struct file *file, void *priv, 1609 + struct v4l2_frmsizeenum *fsize) 1610 + { 1611 + struct vpfe_device *vpfe = video_drvdata(file); 1612 + 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; 1616 + struct vpfe_fmt *fmt; 1617 + int ret; 1618 + 1619 + vpfe_dbg(2, vpfe, "vpfe_enum_size\n"); 1620 + 1621 + /* check for valid format */ 1622 + fmt = find_format_by_pix(fsize->pixel_format); 1623 + if (!fmt) { 1624 + vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", 1625 + fsize->pixel_format); 1626 + return -EINVAL; 1627 + } 1628 + 1629 + memset(fsize->reserved, 0x0, sizeof(fsize->reserved)); 1630 + 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 + memset(&fse, 0x0, sizeof(fse)); 1645 + fse.index = fsize->index; 1646 + fse.pad = 0; 1647 + fse.code = mbus.code; 1648 + ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse); 1649 + if (ret) 1650 + return -EINVAL; 1651 + 1652 + vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", 1653 + fse.index, fse.code, fse.min_width, fse.max_width, 1654 + fse.min_height, fse.max_height); 1655 + 1656 + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; 1657 + fsize->discrete.width = fse.max_width; 1658 + fsize->discrete.height = fse.max_height; 1659 + 1660 + vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d pixformat: %s size: %dx%d\n", 1661 + fsize->index, print_fourcc(fsize->pixel_format), 1662 + fsize->discrete.width, fsize->discrete.height); 1663 + 1664 + return 0; 1665 + } 1666 + 1667 + /* 1668 + * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a 1669 + * given app input index 1670 + */ 1671 + static int 1672 + vpfe_get_subdev_input_index(struct vpfe_device *vpfe, 1673 + int *subdev_index, 1674 + int *subdev_input_index, 1675 + int app_input_index) 1676 + { 1677 + struct vpfe_config *cfg = vpfe->cfg; 1678 + struct vpfe_subdev_info *sdinfo; 1679 + int i, j = 0; 1680 + 1681 + for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { 1682 + sdinfo = &cfg->sub_devs[i]; 1683 + if (app_input_index < (j + 1)) { 1684 + *subdev_index = i; 1685 + *subdev_input_index = app_input_index - j; 1686 + return 0; 1687 + } 1688 + j++; 1689 + } 1690 + return -EINVAL; 1691 + } 1692 + 1693 + /* 1694 + * vpfe_get_app_input - Get app input index for a given subdev input index 1695 + * driver stores the input index of the current sub device and translate it 1696 + * when application request the current input 1697 + */ 1698 + static int vpfe_get_app_input_index(struct vpfe_device *vpfe, 1699 + int *app_input_index) 1700 + { 1701 + struct vpfe_config *cfg = vpfe->cfg; 1702 + struct vpfe_subdev_info *sdinfo; 1703 + int i, j = 0; 1704 + 1705 + for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { 1706 + sdinfo = &cfg->sub_devs[i]; 1707 + if (!strcmp(sdinfo->name, vpfe->current_subdev->name)) { 1708 + if (vpfe->current_input >= 1) 1709 + return -1; 1710 + *app_input_index = j + vpfe->current_input; 1711 + return 0; 1712 + } 1713 + j++; 1714 + } 1715 + return -EINVAL; 1716 + } 1717 + 1718 + static int vpfe_enum_input(struct file *file, void *priv, 1719 + struct v4l2_input *inp) 1720 + { 1721 + struct vpfe_device *vpfe = video_drvdata(file); 1722 + struct vpfe_subdev_info *sdinfo; 1723 + int subdev, index; 1724 + 1725 + vpfe_dbg(2, vpfe, "vpfe_enum_input\n"); 1726 + 1727 + if (vpfe_get_subdev_input_index(vpfe, &subdev, &index, 1728 + inp->index) < 0) { 1729 + vpfe_dbg(1, vpfe, 1730 + "input information not found for the subdev\n"); 1731 + return -EINVAL; 1732 + } 1733 + sdinfo = &vpfe->cfg->sub_devs[subdev]; 1734 + *inp = sdinfo->inputs[index]; 1735 + 1736 + return 0; 1737 + } 1738 + 1739 + static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) 1740 + { 1741 + struct vpfe_device *vpfe = video_drvdata(file); 1742 + 1743 + vpfe_dbg(2, vpfe, "vpfe_g_input\n"); 1744 + 1745 + return vpfe_get_app_input_index(vpfe, index); 1746 + } 1747 + 1748 + /* Assumes caller is holding vpfe_dev->lock */ 1749 + static int vpfe_set_input(struct vpfe_device *vpfe, unsigned int index) 1750 + { 1751 + int subdev_index = 0, inp_index = 0; 1752 + struct vpfe_subdev_info *sdinfo; 1753 + struct vpfe_route *route; 1754 + u32 input, output; 1755 + int ret; 1756 + 1757 + vpfe_dbg(2, vpfe, "vpfe_set_input: index: %d\n", index); 1758 + 1759 + /* If streaming is started, return error */ 1760 + if (vb2_is_busy(&vpfe->buffer_queue)) { 1761 + vpfe_err(vpfe, "%s device busy\n", __func__); 1762 + return -EBUSY; 1763 + } 1764 + ret = vpfe_get_subdev_input_index(vpfe, 1765 + &subdev_index, 1766 + &inp_index, 1767 + index); 1768 + if (ret < 0) { 1769 + vpfe_err(vpfe, "invalid input index: %d\n", index); 1770 + goto get_out; 1771 + } 1772 + 1773 + sdinfo = &vpfe->cfg->sub_devs[subdev_index]; 1774 + sdinfo->sd = vpfe->sd[subdev_index]; 1775 + route = &sdinfo->routes[inp_index]; 1776 + if (route && sdinfo->can_route) { 1777 + input = route->input; 1778 + output = route->output; 1779 + if (sdinfo->sd) { 1780 + ret = v4l2_subdev_call(sdinfo->sd, video, 1781 + s_routing, input, output, 0); 1782 + if (ret) { 1783 + vpfe_err(vpfe, "s_routing failed\n"); 1784 + ret = -EINVAL; 1785 + goto get_out; 1786 + } 1787 + } 1788 + 1789 + } 1790 + 1791 + vpfe->current_subdev = sdinfo; 1792 + if (sdinfo->sd) 1793 + vpfe->v4l2_dev.ctrl_handler = sdinfo->sd->ctrl_handler; 1794 + vpfe->current_input = index; 1795 + vpfe->std_index = 0; 1796 + 1797 + /* set the bus/interface parameter for the sub device in ccdc */ 1798 + ret = vpfe_ccdc_set_hw_if_params(&vpfe->ccdc, &sdinfo->vpfe_param); 1799 + if (ret) 1800 + return ret; 1801 + 1802 + /* set the default image parameters in the device */ 1803 + return vpfe_config_image_format(vpfe, 1804 + vpfe_standards[vpfe->std_index].std_id); 1805 + 1806 + get_out: 1807 + return ret; 1808 + } 1809 + 1810 + static int vpfe_s_input(struct file *file, void *priv, unsigned int index) 1811 + { 1812 + struct vpfe_device *vpfe = video_drvdata(file); 1813 + 1814 + vpfe_dbg(2, vpfe, 1815 + "vpfe_s_input: index: %d\n", index); 1816 + 1817 + return vpfe_set_input(vpfe, index); 1818 + } 1819 + 1820 + static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) 1821 + { 1822 + struct vpfe_device *vpfe = video_drvdata(file); 1823 + struct vpfe_subdev_info *sdinfo; 1824 + 1825 + vpfe_dbg(2, vpfe, "vpfe_querystd\n"); 1826 + 1827 + sdinfo = vpfe->current_subdev; 1828 + if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD)) 1829 + return -ENODATA; 1830 + 1831 + /* Call querystd function of decoder device */ 1832 + return v4l2_device_call_until_err(&vpfe->v4l2_dev, sdinfo->grp_id, 1833 + video, querystd, std_id); 1834 + } 1835 + 1836 + static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) 1837 + { 1838 + struct vpfe_device *vpfe = video_drvdata(file); 1839 + struct vpfe_subdev_info *sdinfo; 1840 + int ret; 1841 + 1842 + vpfe_dbg(2, vpfe, "vpfe_s_std\n"); 1843 + 1844 + sdinfo = vpfe->current_subdev; 1845 + if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD)) 1846 + return -ENODATA; 1847 + 1848 + /* If streaming is started, return error */ 1849 + if (vb2_is_busy(&vpfe->buffer_queue)) { 1850 + vpfe_err(vpfe, "%s device busy\n", __func__); 1851 + ret = -EBUSY; 1852 + return ret; 1853 + } 1854 + 1855 + ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, sdinfo->grp_id, 1856 + video, s_std, std_id); 1857 + if (ret < 0) { 1858 + vpfe_err(vpfe, "Failed to set standard\n"); 1859 + return ret; 1860 + } 1861 + ret = vpfe_config_image_format(vpfe, std_id); 1862 + 1863 + return ret; 1864 + } 1865 + 1866 + static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) 1867 + { 1868 + struct vpfe_device *vpfe = video_drvdata(file); 1869 + struct vpfe_subdev_info *sdinfo; 1870 + 1871 + vpfe_dbg(2, vpfe, "vpfe_g_std\n"); 1872 + 1873 + sdinfo = vpfe->current_subdev; 1874 + if (sdinfo->inputs[0].capabilities != V4L2_IN_CAP_STD) 1875 + return -ENODATA; 1876 + 1877 + *std_id = vpfe_standards[vpfe->std_index].std_id; 1878 + 1879 + return 0; 1880 + } 1881 + 1882 + /* 1883 + * vpfe_calculate_offsets : This function calculates buffers offset 1884 + * for top and bottom field 1885 + */ 1886 + static void vpfe_calculate_offsets(struct vpfe_device *vpfe) 1887 + { 1888 + struct v4l2_rect image_win; 1889 + 1890 + vpfe_dbg(2, vpfe, "vpfe_calculate_offsets\n"); 1891 + 1892 + vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win); 1893 + vpfe->field_off = image_win.height * image_win.width; 1894 + } 1895 + 1896 + /* 1897 + * vpfe_queue_setup - Callback function for buffer setup. 1898 + * @vq: vb2_queue ptr 1899 + * @fmt: v4l2 format 1900 + * @nbuffers: ptr to number of buffers requested by application 1901 + * @nplanes:: contains number of distinct video planes needed to hold a frame 1902 + * @sizes[]: contains the size (in bytes) of each plane. 1903 + * @alloc_ctxs: ptr to allocation context 1904 + * 1905 + * This callback function is called when reqbuf() is called to adjust 1906 + * the buffer count and buffer size 1907 + */ 1908 + static int vpfe_queue_setup(struct vb2_queue *vq, 1909 + const struct v4l2_format *fmt, 1910 + unsigned int *nbuffers, unsigned int *nplanes, 1911 + unsigned int sizes[], void *alloc_ctxs[]) 1912 + { 1913 + struct vpfe_device *vpfe = vb2_get_drv_priv(vq); 1914 + 1915 + if (fmt && fmt->fmt.pix.sizeimage < vpfe->fmt.fmt.pix.sizeimage) 1916 + return -EINVAL; 1917 + 1918 + if (vq->num_buffers + *nbuffers < 3) 1919 + *nbuffers = 3 - vq->num_buffers; 1920 + 1921 + *nplanes = 1; 1922 + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : vpfe->fmt.fmt.pix.sizeimage; 1923 + alloc_ctxs[0] = vpfe->alloc_ctx; 1924 + 1925 + vpfe_dbg(1, vpfe, 1926 + "nbuffers=%d, size=%u\n", *nbuffers, sizes[0]); 1927 + 1928 + /* Calculate field offset */ 1929 + vpfe_calculate_offsets(vpfe); 1930 + 1931 + return 0; 1932 + } 1933 + 1934 + /* 1935 + * vpfe_buffer_prepare : callback function for buffer prepare 1936 + * @vb: ptr to vb2_buffer 1937 + * 1938 + * This is the callback function for buffer prepare when vb2_qbuf() 1939 + * function is called. The buffer is prepared and user space virtual address 1940 + * or user address is converted into physical address 1941 + */ 1942 + static int vpfe_buffer_prepare(struct vb2_buffer *vb) 1943 + { 1944 + struct vpfe_device *vpfe = vb2_get_drv_priv(vb->vb2_queue); 1945 + 1946 + vb2_set_plane_payload(vb, 0, vpfe->fmt.fmt.pix.sizeimage); 1947 + 1948 + if (vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) 1949 + return -EINVAL; 1950 + 1951 + vb->v4l2_buf.field = vpfe->fmt.fmt.pix.field; 1952 + 1953 + return 0; 1954 + } 1955 + 1956 + /* 1957 + * vpfe_buffer_queue : Callback function to add buffer to DMA queue 1958 + * @vb: ptr to vb2_buffer 1959 + */ 1960 + static void vpfe_buffer_queue(struct vb2_buffer *vb) 1961 + { 1962 + struct vpfe_device *vpfe = vb2_get_drv_priv(vb->vb2_queue); 1963 + struct vpfe_cap_buffer *buf = to_vpfe_buffer(vb); 1964 + unsigned long flags = 0; 1965 + 1966 + /* add the buffer to the DMA queue */ 1967 + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); 1968 + list_add_tail(&buf->list, &vpfe->dma_queue); 1969 + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); 1970 + } 1971 + 1972 + /* 1973 + * vpfe_start_streaming : Starts the DMA engine for streaming 1974 + * @vb: ptr to vb2_buffer 1975 + * @count: number of buffers 1976 + */ 1977 + static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) 1978 + { 1979 + struct vpfe_device *vpfe = vb2_get_drv_priv(vq); 1980 + struct vpfe_cap_buffer *buf, *tmp; 1981 + struct vpfe_subdev_info *sdinfo; 1982 + unsigned long flags; 1983 + unsigned long addr; 1984 + int ret; 1985 + 1986 + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); 1987 + 1988 + vpfe->field = 0; 1989 + vpfe->sequence = 0; 1990 + 1991 + sdinfo = vpfe->current_subdev; 1992 + 1993 + vpfe_attach_irq(vpfe); 1994 + 1995 + if (vpfe->ccdc.ccdc_cfg.if_type == VPFE_RAW_BAYER) 1996 + vpfe_ccdc_config_raw(&vpfe->ccdc); 1997 + else 1998 + vpfe_ccdc_config_ycbcr(&vpfe->ccdc); 1999 + 2000 + /* Get the next frame from the buffer queue */ 2001 + vpfe->next_frm = list_entry(vpfe->dma_queue.next, 2002 + struct vpfe_cap_buffer, list); 2003 + vpfe->cur_frm = vpfe->next_frm; 2004 + /* Remove buffer from the buffer queue */ 2005 + list_del(&vpfe->cur_frm->list); 2006 + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); 2007 + 2008 + addr = vb2_dma_contig_plane_dma_addr(&vpfe->cur_frm->vb, 0); 2009 + 2010 + vpfe_set_sdr_addr(&vpfe->ccdc, (unsigned long)(addr)); 2011 + 2012 + vpfe_pcr_enable(&vpfe->ccdc, 1); 2013 + 2014 + ret = v4l2_subdev_call(sdinfo->sd, video, s_stream, 1); 2015 + if (ret < 0) { 2016 + vpfe_err(vpfe, "Error in attaching interrupt handle\n"); 2017 + goto err; 2018 + } 2019 + 2020 + return 0; 2021 + 2022 + err: 2023 + list_for_each_entry_safe(buf, tmp, &vpfe->dma_queue, list) { 2024 + list_del(&buf->list); 2025 + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); 2026 + } 2027 + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); 2028 + 2029 + return ret; 2030 + } 2031 + 2032 + /* 2033 + * vpfe_stop_streaming : Stop the DMA engine 2034 + * @vq: ptr to vb2_queue 2035 + * 2036 + * This callback stops the DMA engine and any remaining buffers 2037 + * in the DMA queue are released. 2038 + */ 2039 + static void vpfe_stop_streaming(struct vb2_queue *vq) 2040 + { 2041 + struct vpfe_device *vpfe = vb2_get_drv_priv(vq); 2042 + struct vpfe_subdev_info *sdinfo; 2043 + unsigned long flags; 2044 + int ret; 2045 + 2046 + vpfe_pcr_enable(&vpfe->ccdc, 0); 2047 + 2048 + vpfe_detach_irq(vpfe); 2049 + 2050 + sdinfo = vpfe->current_subdev; 2051 + ret = v4l2_subdev_call(sdinfo->sd, video, s_stream, 0); 2052 + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) 2053 + vpfe_dbg(1, vpfe, "stream off failed in subdev\n"); 2054 + 2055 + /* release all active buffers */ 2056 + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); 2057 + if (vpfe->cur_frm == vpfe->next_frm) { 2058 + vb2_buffer_done(&vpfe->cur_frm->vb, VB2_BUF_STATE_ERROR); 2059 + } else { 2060 + if (vpfe->cur_frm != NULL) 2061 + vb2_buffer_done(&vpfe->cur_frm->vb, 2062 + VB2_BUF_STATE_ERROR); 2063 + if (vpfe->next_frm != NULL) 2064 + vb2_buffer_done(&vpfe->next_frm->vb, 2065 + VB2_BUF_STATE_ERROR); 2066 + } 2067 + 2068 + while (!list_empty(&vpfe->dma_queue)) { 2069 + vpfe->next_frm = list_entry(vpfe->dma_queue.next, 2070 + struct vpfe_cap_buffer, list); 2071 + list_del(&vpfe->next_frm->list); 2072 + vb2_buffer_done(&vpfe->next_frm->vb, VB2_BUF_STATE_ERROR); 2073 + } 2074 + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); 2075 + } 2076 + 2077 + static int vpfe_cropcap(struct file *file, void *priv, 2078 + struct v4l2_cropcap *crop) 2079 + { 2080 + struct vpfe_device *vpfe = video_drvdata(file); 2081 + 2082 + vpfe_dbg(2, vpfe, "vpfe_cropcap\n"); 2083 + 2084 + if (vpfe->std_index >= ARRAY_SIZE(vpfe_standards)) 2085 + return -EINVAL; 2086 + 2087 + memset(crop, 0, sizeof(struct v4l2_cropcap)); 2088 + 2089 + crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2090 + crop->defrect.width = vpfe_standards[vpfe->std_index].width; 2091 + crop->bounds.width = crop->defrect.width; 2092 + crop->defrect.height = vpfe_standards[vpfe->std_index].height; 2093 + crop->bounds.height = crop->defrect.height; 2094 + crop->pixelaspect = vpfe_standards[vpfe->std_index].pixelaspect; 2095 + 2096 + return 0; 2097 + } 2098 + 2099 + static int 2100 + vpfe_g_selection(struct file *file, void *fh, struct v4l2_selection *s) 2101 + { 2102 + struct vpfe_device *vpfe = video_drvdata(file); 2103 + 2104 + switch (s->target) { 2105 + case V4L2_SEL_TGT_CROP_BOUNDS: 2106 + case V4L2_SEL_TGT_CROP_DEFAULT: 2107 + s->r.left = s->r.top = 0; 2108 + s->r.width = vpfe->crop.width; 2109 + s->r.height = vpfe->crop.height; 2110 + break; 2111 + 2112 + case V4L2_SEL_TGT_CROP: 2113 + s->r = vpfe->crop; 2114 + break; 2115 + 2116 + default: 2117 + return -EINVAL; 2118 + } 2119 + 2120 + return 0; 2121 + } 2122 + 2123 + static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) 2124 + { 2125 + if (a->left < b->left || a->top < b->top) 2126 + return 0; 2127 + 2128 + if (a->left + a->width > b->left + b->width) 2129 + return 0; 2130 + 2131 + if (a->top + a->height > b->top + b->height) 2132 + return 0; 2133 + 2134 + return 1; 2135 + } 2136 + 2137 + static int 2138 + vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) 2139 + { 2140 + struct vpfe_device *vpfe = video_drvdata(file); 2141 + struct v4l2_rect cr = vpfe->crop; 2142 + struct v4l2_rect r = s->r; 2143 + 2144 + /* If streaming is started, return error */ 2145 + if (vb2_is_busy(&vpfe->buffer_queue)) { 2146 + vpfe_err(vpfe, "%s device busy\n", __func__); 2147 + return -EBUSY; 2148 + } 2149 + 2150 + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || 2151 + s->target != V4L2_SEL_TGT_CROP) 2152 + return -EINVAL; 2153 + 2154 + v4l_bound_align_image(&r.width, 0, cr.width, 0, 2155 + &r.height, 0, cr.height, 0, 0); 2156 + 2157 + r.left = clamp_t(unsigned int, r.left, 0, cr.width - r.width); 2158 + r.top = clamp_t(unsigned int, r.top, 0, cr.height - r.height); 2159 + 2160 + if (s->flags & V4L2_SEL_FLAG_LE && !enclosed_rectangle(&r, &s->r)) 2161 + return -ERANGE; 2162 + 2163 + if (s->flags & V4L2_SEL_FLAG_GE && !enclosed_rectangle(&s->r, &r)) 2164 + return -ERANGE; 2165 + 2166 + s->r = vpfe->crop = r; 2167 + 2168 + vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, vpfe->bpp); 2169 + vpfe->fmt.fmt.pix.width = r.width; 2170 + vpfe->fmt.fmt.pix.height = r.height; 2171 + vpfe->fmt.fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc); 2172 + vpfe->fmt.fmt.pix.sizeimage = vpfe->fmt.fmt.pix.bytesperline * 2173 + vpfe->fmt.fmt.pix.height; 2174 + 2175 + vpfe_dbg(1, vpfe, "cropped (%d,%d)/%dx%d of %dx%d\n", 2176 + r.left, r.top, r.width, r.height, cr.width, cr.height); 2177 + 2178 + return 0; 2179 + } 2180 + 2181 + static long vpfe_ioctl_default(struct file *file, void *priv, 2182 + bool valid_prio, unsigned int cmd, void *param) 2183 + { 2184 + struct vpfe_device *vpfe = video_drvdata(file); 2185 + int ret; 2186 + 2187 + vpfe_dbg(2, vpfe, "vpfe_ioctl_default\n"); 2188 + 2189 + if (!valid_prio) { 2190 + vpfe_err(vpfe, "%s device busy\n", __func__); 2191 + return -EBUSY; 2192 + } 2193 + 2194 + /* If streaming is started, return error */ 2195 + if (vb2_is_busy(&vpfe->buffer_queue)) { 2196 + vpfe_err(vpfe, "%s device busy\n", __func__); 2197 + return -EBUSY; 2198 + } 2199 + 2200 + switch (cmd) { 2201 + case VIDIOC_AM437X_CCDC_CFG: 2202 + ret = vpfe_ccdc_set_params(&vpfe->ccdc, param); 2203 + if (ret) { 2204 + vpfe_dbg(2, vpfe, 2205 + "Error setting parameters in CCDC\n"); 2206 + return ret; 2207 + } 2208 + ret = vpfe_get_ccdc_image_format(vpfe, 2209 + &vpfe->fmt); 2210 + if (ret < 0) { 2211 + vpfe_dbg(2, vpfe, 2212 + "Invalid image format at CCDC\n"); 2213 + return ret; 2214 + } 2215 + break; 2216 + 2217 + default: 2218 + ret = -ENOTTY; 2219 + break; 2220 + } 2221 + 2222 + return ret; 2223 + } 2224 + 2225 + static const struct vb2_ops vpfe_video_qops = { 2226 + .wait_prepare = vb2_ops_wait_prepare, 2227 + .wait_finish = vb2_ops_wait_finish, 2228 + .queue_setup = vpfe_queue_setup, 2229 + .buf_prepare = vpfe_buffer_prepare, 2230 + .buf_queue = vpfe_buffer_queue, 2231 + .start_streaming = vpfe_start_streaming, 2232 + .stop_streaming = vpfe_stop_streaming, 2233 + }; 2234 + 2235 + /* vpfe capture driver file operations */ 2236 + static const struct v4l2_file_operations vpfe_fops = { 2237 + .owner = THIS_MODULE, 2238 + .open = vpfe_open, 2239 + .release = vpfe_release, 2240 + .read = vb2_fop_read, 2241 + .poll = vb2_fop_poll, 2242 + .unlocked_ioctl = video_ioctl2, 2243 + .mmap = vb2_fop_mmap, 2244 + }; 2245 + 2246 + /* vpfe capture ioctl operations */ 2247 + static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { 2248 + .vidioc_querycap = vpfe_querycap, 2249 + .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt, 2250 + .vidioc_g_fmt_vid_cap = vpfe_g_fmt, 2251 + .vidioc_s_fmt_vid_cap = vpfe_s_fmt, 2252 + .vidioc_try_fmt_vid_cap = vpfe_try_fmt, 2253 + 2254 + .vidioc_enum_framesizes = vpfe_enum_size, 2255 + 2256 + .vidioc_enum_input = vpfe_enum_input, 2257 + .vidioc_g_input = vpfe_g_input, 2258 + .vidioc_s_input = vpfe_s_input, 2259 + 2260 + .vidioc_querystd = vpfe_querystd, 2261 + .vidioc_s_std = vpfe_s_std, 2262 + .vidioc_g_std = vpfe_g_std, 2263 + 2264 + .vidioc_reqbufs = vb2_ioctl_reqbufs, 2265 + .vidioc_create_bufs = vb2_ioctl_create_bufs, 2266 + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 2267 + .vidioc_querybuf = vb2_ioctl_querybuf, 2268 + .vidioc_qbuf = vb2_ioctl_qbuf, 2269 + .vidioc_dqbuf = vb2_ioctl_dqbuf, 2270 + .vidioc_expbuf = vb2_ioctl_expbuf, 2271 + .vidioc_streamon = vb2_ioctl_streamon, 2272 + .vidioc_streamoff = vb2_ioctl_streamoff, 2273 + 2274 + .vidioc_log_status = v4l2_ctrl_log_status, 2275 + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 2276 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 2277 + 2278 + .vidioc_cropcap = vpfe_cropcap, 2279 + .vidioc_g_selection = vpfe_g_selection, 2280 + .vidioc_s_selection = vpfe_s_selection, 2281 + 2282 + .vidioc_default = vpfe_ioctl_default, 2283 + }; 2284 + 2285 + static int 2286 + vpfe_async_bound(struct v4l2_async_notifier *notifier, 2287 + struct v4l2_subdev *subdev, 2288 + struct v4l2_async_subdev *asd) 2289 + { 2290 + struct vpfe_device *vpfe = container_of(notifier->v4l2_dev, 2291 + struct vpfe_device, v4l2_dev); 2292 + struct v4l2_subdev_mbus_code_enum mbus_code; 2293 + struct vpfe_subdev_info *sdinfo; 2294 + bool found = false; 2295 + int i, j; 2296 + 2297 + vpfe_dbg(1, vpfe, "vpfe_async_bound\n"); 2298 + 2299 + for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { 2300 + sdinfo = &vpfe->cfg->sub_devs[i]; 2301 + 2302 + if (!strcmp(sdinfo->name, subdev->name)) { 2303 + vpfe->sd[i] = subdev; 2304 + vpfe_info(vpfe, 2305 + "v4l2 sub device %s registered\n", 2306 + subdev->name); 2307 + vpfe->sd[i]->grp_id = 2308 + sdinfo->grp_id; 2309 + /* update tvnorms from the sub devices */ 2310 + for (j = 0; j < 1; j++) 2311 + vpfe->video_dev->tvnorms |= 2312 + sdinfo->inputs[j].std; 2313 + 2314 + found = true; 2315 + break; 2316 + } 2317 + } 2318 + 2319 + if (!found) { 2320 + vpfe_info(vpfe, "sub device (%s) not matched\n", subdev->name); 2321 + return -EINVAL; 2322 + } 2323 + 2324 + /* setup the supported formats & indexes */ 2325 + for (j = 0, i = 0; ; ++j) { 2326 + struct vpfe_fmt *fmt; 2327 + int ret; 2328 + 2329 + memset(&mbus_code, 0, sizeof(mbus_code)); 2330 + mbus_code.index = j; 2331 + ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, 2332 + NULL, &mbus_code); 2333 + if (ret) 2334 + break; 2335 + 2336 + fmt = find_format_by_code(mbus_code.code); 2337 + if (!fmt) 2338 + continue; 2339 + 2340 + fmt->supported = true; 2341 + fmt->index = i++; 2342 + } 2343 + 2344 + return 0; 2345 + } 2346 + 2347 + static int vpfe_probe_complete(struct vpfe_device *vpfe) 2348 + { 2349 + struct video_device *vdev; 2350 + struct vb2_queue *q; 2351 + int err; 2352 + 2353 + spin_lock_init(&vpfe->dma_queue_lock); 2354 + mutex_init(&vpfe->lock); 2355 + 2356 + vpfe->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2357 + 2358 + /* set first sub device as current one */ 2359 + vpfe->current_subdev = &vpfe->cfg->sub_devs[0]; 2360 + vpfe->v4l2_dev.ctrl_handler = vpfe->sd[0]->ctrl_handler; 2361 + 2362 + err = vpfe_set_input(vpfe, 0); 2363 + if (err) 2364 + goto probe_out; 2365 + 2366 + /* Initialize videobuf2 queue as per the buffer type */ 2367 + vpfe->alloc_ctx = vb2_dma_contig_init_ctx(vpfe->pdev); 2368 + if (IS_ERR(vpfe->alloc_ctx)) { 2369 + vpfe_err(vpfe, "Failed to get the context\n"); 2370 + err = PTR_ERR(vpfe->alloc_ctx); 2371 + goto probe_out; 2372 + } 2373 + 2374 + q = &vpfe->buffer_queue; 2375 + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2376 + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; 2377 + q->drv_priv = vpfe; 2378 + q->ops = &vpfe_video_qops; 2379 + q->mem_ops = &vb2_dma_contig_memops; 2380 + q->buf_struct_size = sizeof(struct vpfe_cap_buffer); 2381 + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 2382 + q->lock = &vpfe->lock; 2383 + q->min_buffers_needed = 1; 2384 + 2385 + err = vb2_queue_init(q); 2386 + if (err) { 2387 + vpfe_err(vpfe, "vb2_queue_init() failed\n"); 2388 + vb2_dma_contig_cleanup_ctx(vpfe->alloc_ctx); 2389 + goto probe_out; 2390 + } 2391 + 2392 + INIT_LIST_HEAD(&vpfe->dma_queue); 2393 + 2394 + vdev = vpfe->video_dev; 2395 + strlcpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name)); 2396 + vdev->release = video_device_release; 2397 + vdev->fops = &vpfe_fops; 2398 + vdev->ioctl_ops = &vpfe_ioctl_ops; 2399 + vdev->v4l2_dev = &vpfe->v4l2_dev; 2400 + vdev->vfl_dir = VFL_DIR_RX; 2401 + vdev->queue = q; 2402 + vdev->lock = &vpfe->lock; 2403 + video_set_drvdata(vdev, vpfe); 2404 + err = video_register_device(vpfe->video_dev, VFL_TYPE_GRABBER, -1); 2405 + if (err) { 2406 + vpfe_err(vpfe, 2407 + "Unable to register video device.\n"); 2408 + goto probe_out; 2409 + } 2410 + 2411 + return 0; 2412 + 2413 + probe_out: 2414 + v4l2_device_unregister(&vpfe->v4l2_dev); 2415 + return err; 2416 + } 2417 + 2418 + static int vpfe_async_complete(struct v4l2_async_notifier *notifier) 2419 + { 2420 + struct vpfe_device *vpfe = container_of(notifier->v4l2_dev, 2421 + struct vpfe_device, v4l2_dev); 2422 + 2423 + return vpfe_probe_complete(vpfe); 2424 + } 2425 + 2426 + static struct vpfe_config * 2427 + vpfe_get_pdata(struct platform_device *pdev) 2428 + { 2429 + struct device_node *endpoint = NULL, *rem = NULL; 2430 + struct v4l2_of_endpoint bus_cfg; 2431 + struct vpfe_subdev_info *sdinfo; 2432 + struct vpfe_config *pdata; 2433 + unsigned int flags; 2434 + unsigned int i; 2435 + int err; 2436 + 2437 + dev_dbg(&pdev->dev, "vpfe_get_pdata\n"); 2438 + 2439 + if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) 2440 + return pdev->dev.platform_data; 2441 + 2442 + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 2443 + if (!pdata) 2444 + return NULL; 2445 + 2446 + for (i = 0; ; i++) { 2447 + endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, 2448 + endpoint); 2449 + if (!endpoint) 2450 + break; 2451 + 2452 + sdinfo = &pdata->sub_devs[i]; 2453 + sdinfo->grp_id = 0; 2454 + 2455 + /* we only support camera */ 2456 + sdinfo->inputs[0].index = i; 2457 + strcpy(sdinfo->inputs[0].name, "Camera"); 2458 + sdinfo->inputs[0].type = V4L2_INPUT_TYPE_CAMERA; 2459 + sdinfo->inputs[0].std = V4L2_STD_ALL; 2460 + sdinfo->inputs[0].capabilities = V4L2_IN_CAP_STD; 2461 + 2462 + sdinfo->can_route = 0; 2463 + sdinfo->routes = NULL; 2464 + 2465 + of_property_read_u32(endpoint, "ti,am437x-vpfe-interface", 2466 + &sdinfo->vpfe_param.if_type); 2467 + if (sdinfo->vpfe_param.if_type < 0 || 2468 + sdinfo->vpfe_param.if_type > 4) { 2469 + sdinfo->vpfe_param.if_type = VPFE_RAW_BAYER; 2470 + } 2471 + 2472 + err = v4l2_of_parse_endpoint(endpoint, &bus_cfg); 2473 + if (err) { 2474 + dev_err(&pdev->dev, "Could not parse the endpoint\n"); 2475 + goto done; 2476 + } 2477 + 2478 + sdinfo->vpfe_param.bus_width = bus_cfg.bus.parallel.bus_width; 2479 + 2480 + if (sdinfo->vpfe_param.bus_width < 8 || 2481 + sdinfo->vpfe_param.bus_width > 16) { 2482 + dev_err(&pdev->dev, "Invalid bus width.\n"); 2483 + goto done; 2484 + } 2485 + 2486 + flags = bus_cfg.bus.parallel.flags; 2487 + 2488 + if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 2489 + sdinfo->vpfe_param.hdpol = 1; 2490 + 2491 + if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) 2492 + sdinfo->vpfe_param.vdpol = 1; 2493 + 2494 + rem = of_graph_get_remote_port_parent(endpoint); 2495 + if (!rem) { 2496 + dev_err(&pdev->dev, "Remote device at %s not found\n", 2497 + endpoint->full_name); 2498 + goto done; 2499 + } 2500 + 2501 + strncpy(sdinfo->name, rem->name, sizeof(sdinfo->name)); 2502 + 2503 + pdata->asd[i] = devm_kzalloc(&pdev->dev, 2504 + sizeof(struct v4l2_async_subdev), 2505 + GFP_KERNEL); 2506 + pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_OF; 2507 + pdata->asd[i]->match.of.node = rem; 2508 + of_node_put(endpoint); 2509 + of_node_put(rem); 2510 + } 2511 + 2512 + of_node_put(endpoint); 2513 + return pdata; 2514 + 2515 + done: 2516 + of_node_put(endpoint); 2517 + of_node_put(rem); 2518 + return NULL; 2519 + } 2520 + 2521 + /* 2522 + * vpfe_probe : This function creates device entries by register 2523 + * itself to the V4L2 driver and initializes fields of each 2524 + * device objects 2525 + */ 2526 + static int vpfe_probe(struct platform_device *pdev) 2527 + { 2528 + struct vpfe_config *vpfe_cfg = vpfe_get_pdata(pdev); 2529 + struct vpfe_device *vpfe; 2530 + struct vpfe_ccdc *ccdc; 2531 + struct resource *res; 2532 + int ret; 2533 + 2534 + if (!vpfe_cfg) { 2535 + dev_err(&pdev->dev, "No platform data\n"); 2536 + return -EINVAL; 2537 + } 2538 + 2539 + vpfe = devm_kzalloc(&pdev->dev, sizeof(*vpfe), GFP_KERNEL); 2540 + if (!vpfe) 2541 + return -ENOMEM; 2542 + 2543 + vpfe->pdev = &pdev->dev; 2544 + vpfe->cfg = vpfe_cfg; 2545 + ccdc = &vpfe->ccdc; 2546 + 2547 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2548 + ccdc->ccdc_cfg.base_addr = devm_ioremap_resource(&pdev->dev, res); 2549 + if (IS_ERR(ccdc->ccdc_cfg.base_addr)) 2550 + return PTR_ERR(ccdc->ccdc_cfg.base_addr); 2551 + 2552 + vpfe->irq = platform_get_irq(pdev, 0); 2553 + if (vpfe->irq <= 0) { 2554 + dev_err(&pdev->dev, "No IRQ resource\n"); 2555 + return -ENODEV; 2556 + } 2557 + 2558 + ret = devm_request_irq(vpfe->pdev, vpfe->irq, vpfe_isr, 0, 2559 + "vpfe_capture0", vpfe); 2560 + if (ret) { 2561 + dev_err(&pdev->dev, "Unable to request interrupt\n"); 2562 + return -EINVAL; 2563 + } 2564 + 2565 + vpfe->video_dev = video_device_alloc(); 2566 + if (!vpfe->video_dev) { 2567 + dev_err(&pdev->dev, "Unable to allocate video device\n"); 2568 + return -ENOMEM; 2569 + } 2570 + 2571 + ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev); 2572 + if (ret) { 2573 + vpfe_err(vpfe, 2574 + "Unable to register v4l2 device.\n"); 2575 + goto probe_out_video_release; 2576 + } 2577 + 2578 + /* set the driver data in platform device */ 2579 + platform_set_drvdata(pdev, vpfe); 2580 + /* Enabling module functional clock */ 2581 + pm_runtime_enable(&pdev->dev); 2582 + 2583 + /* for now just enable it here instead of waiting for the open */ 2584 + pm_runtime_get_sync(&pdev->dev); 2585 + 2586 + vpfe_ccdc_config_defaults(ccdc); 2587 + 2588 + pm_runtime_put_sync(&pdev->dev); 2589 + 2590 + vpfe->sd = devm_kzalloc(&pdev->dev, sizeof(struct v4l2_subdev *) * 2591 + ARRAY_SIZE(vpfe->cfg->asd), GFP_KERNEL); 2592 + if (!vpfe->sd) { 2593 + ret = -ENOMEM; 2594 + goto probe_out_v4l2_unregister; 2595 + } 2596 + 2597 + vpfe->notifier.subdevs = vpfe->cfg->asd; 2598 + vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd); 2599 + vpfe->notifier.bound = vpfe_async_bound; 2600 + vpfe->notifier.complete = vpfe_async_complete; 2601 + ret = v4l2_async_notifier_register(&vpfe->v4l2_dev, 2602 + &vpfe->notifier); 2603 + if (ret) { 2604 + vpfe_err(vpfe, "Error registering async notifier\n"); 2605 + ret = -EINVAL; 2606 + goto probe_out_v4l2_unregister; 2607 + } 2608 + 2609 + return 0; 2610 + 2611 + probe_out_v4l2_unregister: 2612 + v4l2_device_unregister(&vpfe->v4l2_dev); 2613 + probe_out_video_release: 2614 + if (!video_is_registered(vpfe->video_dev)) 2615 + video_device_release(vpfe->video_dev); 2616 + return ret; 2617 + } 2618 + 2619 + /* 2620 + * vpfe_remove : It un-register device from V4L2 driver 2621 + */ 2622 + static int vpfe_remove(struct platform_device *pdev) 2623 + { 2624 + struct vpfe_device *vpfe = platform_get_drvdata(pdev); 2625 + 2626 + vpfe_dbg(2, vpfe, "vpfe_remove\n"); 2627 + 2628 + pm_runtime_disable(&pdev->dev); 2629 + 2630 + v4l2_async_notifier_unregister(&vpfe->notifier); 2631 + v4l2_device_unregister(&vpfe->v4l2_dev); 2632 + video_unregister_device(vpfe->video_dev); 2633 + 2634 + return 0; 2635 + } 2636 + 2637 + #ifdef CONFIG_PM_SLEEP 2638 + 2639 + static void vpfe_save_context(struct vpfe_ccdc *ccdc) 2640 + { 2641 + ccdc->ccdc_ctx[VPFE_PCR >> 2] = vpfe_reg_read(ccdc, VPFE_PCR); 2642 + ccdc->ccdc_ctx[VPFE_SYNMODE >> 2] = vpfe_reg_read(ccdc, VPFE_SYNMODE); 2643 + ccdc->ccdc_ctx[VPFE_SDOFST >> 2] = vpfe_reg_read(ccdc, VPFE_SDOFST); 2644 + ccdc->ccdc_ctx[VPFE_SDR_ADDR >> 2] = vpfe_reg_read(ccdc, VPFE_SDR_ADDR); 2645 + ccdc->ccdc_ctx[VPFE_CLAMP >> 2] = vpfe_reg_read(ccdc, VPFE_CLAMP); 2646 + ccdc->ccdc_ctx[VPFE_DCSUB >> 2] = vpfe_reg_read(ccdc, VPFE_DCSUB); 2647 + ccdc->ccdc_ctx[VPFE_COLPTN >> 2] = vpfe_reg_read(ccdc, VPFE_COLPTN); 2648 + ccdc->ccdc_ctx[VPFE_BLKCMP >> 2] = vpfe_reg_read(ccdc, VPFE_BLKCMP); 2649 + ccdc->ccdc_ctx[VPFE_VDINT >> 2] = vpfe_reg_read(ccdc, VPFE_VDINT); 2650 + ccdc->ccdc_ctx[VPFE_ALAW >> 2] = vpfe_reg_read(ccdc, VPFE_ALAW); 2651 + ccdc->ccdc_ctx[VPFE_REC656IF >> 2] = vpfe_reg_read(ccdc, VPFE_REC656IF); 2652 + ccdc->ccdc_ctx[VPFE_CCDCFG >> 2] = vpfe_reg_read(ccdc, VPFE_CCDCFG); 2653 + ccdc->ccdc_ctx[VPFE_CULLING >> 2] = vpfe_reg_read(ccdc, VPFE_CULLING); 2654 + ccdc->ccdc_ctx[VPFE_HD_VD_WID >> 2] = vpfe_reg_read(ccdc, 2655 + VPFE_HD_VD_WID); 2656 + ccdc->ccdc_ctx[VPFE_PIX_LINES >> 2] = vpfe_reg_read(ccdc, 2657 + VPFE_PIX_LINES); 2658 + ccdc->ccdc_ctx[VPFE_HORZ_INFO >> 2] = vpfe_reg_read(ccdc, 2659 + VPFE_HORZ_INFO); 2660 + ccdc->ccdc_ctx[VPFE_VERT_START >> 2] = vpfe_reg_read(ccdc, 2661 + VPFE_VERT_START); 2662 + ccdc->ccdc_ctx[VPFE_VERT_LINES >> 2] = vpfe_reg_read(ccdc, 2663 + VPFE_VERT_LINES); 2664 + ccdc->ccdc_ctx[VPFE_HSIZE_OFF >> 2] = vpfe_reg_read(ccdc, 2665 + VPFE_HSIZE_OFF); 2666 + } 2667 + 2668 + static int vpfe_suspend(struct device *dev) 2669 + { 2670 + struct platform_device *pdev = to_platform_device(dev); 2671 + struct vpfe_device *vpfe = platform_get_drvdata(pdev); 2672 + struct vpfe_ccdc *ccdc = &vpfe->ccdc; 2673 + 2674 + /* if streaming has not started we don't care */ 2675 + if (!vb2_start_streaming_called(&vpfe->buffer_queue)) 2676 + return 0; 2677 + 2678 + pm_runtime_get_sync(dev); 2679 + vpfe_config_enable(ccdc, 1); 2680 + 2681 + /* Save VPFE context */ 2682 + vpfe_save_context(ccdc); 2683 + 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); 2690 + 2691 + /* Select sleep pin state */ 2692 + pinctrl_pm_select_sleep_state(dev); 2693 + 2694 + return 0; 2695 + } 2696 + 2697 + static void vpfe_restore_context(struct vpfe_ccdc *ccdc) 2698 + { 2699 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SYNMODE >> 2], VPFE_SYNMODE); 2700 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CULLING >> 2], VPFE_CULLING); 2701 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SDOFST >> 2], VPFE_SDOFST); 2702 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SDR_ADDR >> 2], VPFE_SDR_ADDR); 2703 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CLAMP >> 2], VPFE_CLAMP); 2704 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_DCSUB >> 2], VPFE_DCSUB); 2705 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_COLPTN >> 2], VPFE_COLPTN); 2706 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_BLKCMP >> 2], VPFE_BLKCMP); 2707 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VDINT >> 2], VPFE_VDINT); 2708 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_ALAW >> 2], VPFE_ALAW); 2709 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_REC656IF >> 2], VPFE_REC656IF); 2710 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CCDCFG >> 2], VPFE_CCDCFG); 2711 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_PCR >> 2], VPFE_PCR); 2712 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HD_VD_WID >> 2], 2713 + VPFE_HD_VD_WID); 2714 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_PIX_LINES >> 2], 2715 + VPFE_PIX_LINES); 2716 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HORZ_INFO >> 2], 2717 + VPFE_HORZ_INFO); 2718 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VERT_START >> 2], 2719 + VPFE_VERT_START); 2720 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VERT_LINES >> 2], 2721 + VPFE_VERT_LINES); 2722 + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HSIZE_OFF >> 2], 2723 + VPFE_HSIZE_OFF); 2724 + } 2725 + 2726 + static int vpfe_resume(struct device *dev) 2727 + { 2728 + struct platform_device *pdev = to_platform_device(dev); 2729 + struct vpfe_device *vpfe = platform_get_drvdata(pdev); 2730 + struct vpfe_ccdc *ccdc = &vpfe->ccdc; 2731 + 2732 + /* if streaming has not started we don't care */ 2733 + if (!vb2_start_streaming_called(&vpfe->buffer_queue)) 2734 + return 0; 2735 + 2736 + /* Enable both master and slave clock */ 2737 + pm_runtime_get_sync(dev); 2738 + vpfe_config_enable(ccdc, 1); 2739 + 2740 + /* Restore VPFE context */ 2741 + vpfe_restore_context(ccdc); 2742 + 2743 + vpfe_config_enable(ccdc, 0); 2744 + pm_runtime_put_sync(dev); 2745 + 2746 + /* Select default pin state */ 2747 + pinctrl_pm_select_default_state(dev); 2748 + 2749 + return 0; 2750 + } 2751 + 2752 + #endif 2753 + 2754 + static SIMPLE_DEV_PM_OPS(vpfe_pm_ops, vpfe_suspend, vpfe_resume); 2755 + 2756 + static const struct of_device_id vpfe_of_match[] = { 2757 + { .compatible = "ti,am437x-vpfe", }, 2758 + { /* sentinel */ }, 2759 + }; 2760 + MODULE_DEVICE_TABLE(of, vpfe_of_match); 2761 + 2762 + static struct platform_driver vpfe_driver = { 2763 + .probe = vpfe_probe, 2764 + .remove = vpfe_remove, 2765 + .driver = { 2766 + .name = VPFE_MODULE_NAME, 2767 + .owner = THIS_MODULE, 2768 + .pm = &vpfe_pm_ops, 2769 + .of_match_table = of_match_ptr(vpfe_of_match), 2770 + }, 2771 + }; 2772 + 2773 + module_platform_driver(vpfe_driver); 2774 + 2775 + MODULE_AUTHOR("Texas Instruments"); 2776 + MODULE_DESCRIPTION("TI AM437x VPFE driver"); 2777 + MODULE_LICENSE("GPL"); 2778 + MODULE_VERSION(VPFE_VERSION);
+283
drivers/media/platform/am437x/am437x-vpfe.h
··· 1 + /* 2 + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. 3 + * 4 + * Benoit Parrot <bparrot@ti.com> 5 + * Lad, Prabhakar <prabhakar.csengg@gmail.com> 6 + * 7 + * This program is free software; you may redistribute it and/or modify 8 + * it under the terms of the GNU General Public License as published by 9 + * the Free Software Foundation; version 2 of the License. 10 + * 11 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 12 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 13 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 15 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 16 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 + * SOFTWARE. 19 + */ 20 + 21 + #ifndef AM437X_VPFE_H 22 + #define AM437X_VPFE_H 23 + 24 + #include <linux/am437x-vpfe.h> 25 + #include <linux/clk.h> 26 + #include <linux/device.h> 27 + #include <linux/io.h> 28 + #include <linux/i2c.h> 29 + #include <linux/videodev2.h> 30 + 31 + #include <media/v4l2-dev.h> 32 + #include <media/v4l2-device.h> 33 + #include <media/v4l2-ioctl.h> 34 + #include <media/videobuf2-dma-contig.h> 35 + 36 + #include "am437x-vpfe_regs.h" 37 + 38 + enum vpfe_pin_pol { 39 + VPFE_PINPOL_POSITIVE = 0, 40 + VPFE_PINPOL_NEGATIVE, 41 + }; 42 + 43 + enum vpfe_hw_if_type { 44 + /* Raw Bayer */ 45 + VPFE_RAW_BAYER = 0, 46 + /* BT656 - 8 bit */ 47 + VPFE_BT656, 48 + /* BT656 - 10 bit */ 49 + VPFE_BT656_10BIT, 50 + /* YCbCr - 8 bit with external sync */ 51 + VPFE_YCBCR_SYNC_8, 52 + /* YCbCr - 16 bit with external sync */ 53 + VPFE_YCBCR_SYNC_16, 54 + }; 55 + 56 + /* interface description */ 57 + struct vpfe_hw_if_param { 58 + enum vpfe_hw_if_type if_type; 59 + enum vpfe_pin_pol hdpol; 60 + enum vpfe_pin_pol vdpol; 61 + unsigned int bus_width; 62 + }; 63 + 64 + #define VPFE_MAX_SUBDEV 1 65 + #define VPFE_MAX_INPUTS 1 66 + 67 + struct vpfe_pixel_format { 68 + struct v4l2_fmtdesc fmtdesc; 69 + /* bytes per pixel */ 70 + int bpp; 71 + }; 72 + 73 + struct vpfe_std_info { 74 + int active_pixels; 75 + int active_lines; 76 + /* current frame format */ 77 + int frame_format; 78 + }; 79 + 80 + struct vpfe_route { 81 + u32 input; 82 + u32 output; 83 + }; 84 + 85 + struct vpfe_subdev_info { 86 + char name[32]; 87 + /* Sub device group id */ 88 + int grp_id; 89 + /* inputs available at the sub device */ 90 + struct v4l2_input inputs[VPFE_MAX_INPUTS]; 91 + /* Sub dev routing information for each input */ 92 + struct vpfe_route *routes; 93 + /* check if sub dev supports routing */ 94 + int can_route; 95 + /* ccdc bus/interface configuration */ 96 + struct vpfe_hw_if_param vpfe_param; 97 + struct v4l2_subdev *sd; 98 + }; 99 + 100 + struct vpfe_config { 101 + /* information about each subdev */ 102 + struct vpfe_subdev_info sub_devs[VPFE_MAX_SUBDEV]; 103 + /* Flat array, arranged in groups */ 104 + struct v4l2_async_subdev *asd[VPFE_MAX_SUBDEV]; 105 + }; 106 + 107 + struct vpfe_cap_buffer { 108 + struct vb2_buffer vb; 109 + struct list_head list; 110 + }; 111 + 112 + enum ccdc_pixfmt { 113 + CCDC_PIXFMT_RAW = 0, 114 + CCDC_PIXFMT_YCBCR_16BIT, 115 + CCDC_PIXFMT_YCBCR_8BIT, 116 + }; 117 + 118 + enum ccdc_frmfmt { 119 + CCDC_FRMFMT_PROGRESSIVE = 0, 120 + CCDC_FRMFMT_INTERLACED, 121 + }; 122 + 123 + /* PIXEL ORDER IN MEMORY from LSB to MSB */ 124 + /* only applicable for 8-bit input mode */ 125 + enum ccdc_pixorder { 126 + CCDC_PIXORDER_YCBYCR, 127 + CCDC_PIXORDER_CBYCRY, 128 + }; 129 + 130 + enum ccdc_buftype { 131 + CCDC_BUFTYPE_FLD_INTERLEAVED, 132 + CCDC_BUFTYPE_FLD_SEPARATED 133 + }; 134 + 135 + 136 + /* returns the highest bit used for the gamma */ 137 + static inline u8 ccdc_gamma_width_max_bit(enum vpfe_ccdc_gamma_width width) 138 + { 139 + return 15 - width; 140 + } 141 + 142 + /* returns the highest bit used for this data size */ 143 + static inline u8 ccdc_data_size_max_bit(enum vpfe_ccdc_data_size sz) 144 + { 145 + return sz == VPFE_CCDC_DATA_8BITS ? 7 : 15 - sz; 146 + } 147 + 148 + /* Structure for CCDC configuration parameters for raw capture mode */ 149 + struct ccdc_params_raw { 150 + /* pixel format */ 151 + enum ccdc_pixfmt pix_fmt; 152 + /* progressive or interlaced frame */ 153 + enum ccdc_frmfmt frm_fmt; 154 + struct v4l2_rect win; 155 + /* Current Format Bytes Per Pixels */ 156 + unsigned int bytesperpixel; 157 + /* Current Format Bytes per Lines 158 + * (Aligned to 32 bytes) used for HORZ_INFO 159 + */ 160 + unsigned int bytesperline; 161 + /* field id polarity */ 162 + enum vpfe_pin_pol fid_pol; 163 + /* vertical sync polarity */ 164 + enum vpfe_pin_pol vd_pol; 165 + /* horizontal sync polarity */ 166 + enum vpfe_pin_pol hd_pol; 167 + /* interleaved or separated fields */ 168 + enum ccdc_buftype buf_type; 169 + /* 170 + * enable to store the image in inverse 171 + * order in memory(bottom to top) 172 + */ 173 + unsigned char image_invert_enable; 174 + /* configurable parameters */ 175 + struct vpfe_ccdc_config_params_raw config_params; 176 + }; 177 + 178 + struct ccdc_params_ycbcr { 179 + /* pixel format */ 180 + enum ccdc_pixfmt pix_fmt; 181 + /* progressive or interlaced frame */ 182 + enum ccdc_frmfmt frm_fmt; 183 + struct v4l2_rect win; 184 + /* Current Format Bytes Per Pixels */ 185 + unsigned int bytesperpixel; 186 + /* Current Format Bytes per Lines 187 + * (Aligned to 32 bytes) used for HORZ_INFO 188 + */ 189 + unsigned int bytesperline; 190 + /* field id polarity */ 191 + enum vpfe_pin_pol fid_pol; 192 + /* vertical sync polarity */ 193 + enum vpfe_pin_pol vd_pol; 194 + /* horizontal sync polarity */ 195 + enum vpfe_pin_pol hd_pol; 196 + /* enable BT.656 embedded sync mode */ 197 + int bt656_enable; 198 + /* cb:y:cr:y or y:cb:y:cr in memory */ 199 + enum ccdc_pixorder pix_order; 200 + /* interleaved or separated fields */ 201 + enum ccdc_buftype buf_type; 202 + }; 203 + 204 + /* 205 + * CCDC operational configuration 206 + */ 207 + struct ccdc_config { 208 + /* CCDC interface type */ 209 + enum vpfe_hw_if_type if_type; 210 + /* Raw Bayer configuration */ 211 + struct ccdc_params_raw bayer; 212 + /* YCbCr configuration */ 213 + struct ccdc_params_ycbcr ycbcr; 214 + /* ccdc base address */ 215 + void __iomem *base_addr; 216 + }; 217 + 218 + struct vpfe_ccdc { 219 + struct ccdc_config ccdc_cfg; 220 + u32 ccdc_ctx[VPFE_REG_END / sizeof(u32)]; 221 + }; 222 + 223 + struct vpfe_device { 224 + /* V4l2 specific parameters */ 225 + /* Identifies video device for this channel */ 226 + struct video_device *video_dev; 227 + /* sub devices */ 228 + struct v4l2_subdev **sd; 229 + /* vpfe cfg */ 230 + struct vpfe_config *cfg; 231 + /* V4l2 device */ 232 + struct v4l2_device v4l2_dev; 233 + /* parent device */ 234 + struct device *pdev; 235 + /* subdevice async Notifier */ 236 + struct v4l2_async_notifier notifier; 237 + /* Indicates id of the field which is being displayed */ 238 + unsigned field; 239 + unsigned sequence; 240 + /* current interface type */ 241 + struct vpfe_hw_if_param vpfe_if_params; 242 + /* ptr to currently selected sub device */ 243 + struct vpfe_subdev_info *current_subdev; 244 + /* current input at the sub device */ 245 + int current_input; 246 + /* Keeps track of the information about the standard */ 247 + struct vpfe_std_info std_info; 248 + /* std index into std table */ 249 + int std_index; 250 + /* IRQs used when CCDC output to SDRAM */ 251 + unsigned int irq; 252 + /* Pointer pointing to current v4l2_buffer */ 253 + struct vpfe_cap_buffer *cur_frm; 254 + /* Pointer pointing to next v4l2_buffer */ 255 + struct vpfe_cap_buffer *next_frm; 256 + /* Used to store pixel format */ 257 + struct v4l2_format fmt; 258 + /* Used to store current bytes per pixel based on current format */ 259 + unsigned int bpp; 260 + /* 261 + * used when IMP is chained to store the crop window which 262 + * is different from the image window 263 + */ 264 + struct v4l2_rect crop; 265 + /* Buffer queue used in video-buf */ 266 + struct vb2_queue buffer_queue; 267 + /* Allocator-specific contexts for each plane */ 268 + struct vb2_alloc_ctx *alloc_ctx; 269 + /* Queue of filled frames */ 270 + struct list_head dma_queue; 271 + /* IRQ lock for DMA queue */ 272 + spinlock_t dma_queue_lock; 273 + /* lock used to access this structure */ 274 + struct mutex lock; 275 + /* 276 + * offset where second field starts from the starting of the 277 + * buffer for field separated YCbCr formats 278 + */ 279 + u32 field_off; 280 + struct vpfe_ccdc ccdc; 281 + }; 282 + 283 + #endif /* AM437X_VPFE_H */
+140
drivers/media/platform/am437x/am437x-vpfe_regs.h
··· 1 + /* 2 + * TI AM437x Image Sensor Interface Registers 3 + * 4 + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. 5 + * 6 + * Benoit Parrot <bparrot@ti.com> 7 + * Lad, Prabhakar <prabhakar.csengg@gmail.com> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License version 2 as 11 + * published by the Free Software Foundation. 12 + * 13 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any 14 + * kind, whether express or implied; without even the implied warranty 15 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + */ 18 + 19 + #ifndef AM437X_VPFE_REGS_H 20 + #define AM437X_VPFE_REGS_H 21 + 22 + /* VPFE module register offset */ 23 + #define VPFE_REVISION 0x0 24 + #define VPFE_PCR 0x4 25 + #define VPFE_SYNMODE 0x8 26 + #define VPFE_HD_VD_WID 0xc 27 + #define VPFE_PIX_LINES 0x10 28 + #define VPFE_HORZ_INFO 0x14 29 + #define VPFE_VERT_START 0x18 30 + #define VPFE_VERT_LINES 0x1c 31 + #define VPFE_CULLING 0x20 32 + #define VPFE_HSIZE_OFF 0x24 33 + #define VPFE_SDOFST 0x28 34 + #define VPFE_SDR_ADDR 0x2c 35 + #define VPFE_CLAMP 0x30 36 + #define VPFE_DCSUB 0x34 37 + #define VPFE_COLPTN 0x38 38 + #define VPFE_BLKCMP 0x3c 39 + #define VPFE_VDINT 0x48 40 + #define VPFE_ALAW 0x4c 41 + #define VPFE_REC656IF 0x50 42 + #define VPFE_CCDCFG 0x54 43 + #define VPFE_DMA_CNTL 0x98 44 + #define VPFE_SYSCONFIG 0x104 45 + #define VPFE_CONFIG 0x108 46 + #define VPFE_IRQ_EOI 0x110 47 + #define VPFE_IRQ_STS_RAW 0x114 48 + #define VPFE_IRQ_STS 0x118 49 + #define VPFE_IRQ_EN_SET 0x11c 50 + #define VPFE_IRQ_EN_CLR 0x120 51 + #define VPFE_REG_END 0x124 52 + 53 + /* Define bit fields within selected registers */ 54 + #define VPFE_FID_POL_MASK 1 55 + #define VPFE_FID_POL_SHIFT 4 56 + #define VPFE_HD_POL_MASK 1 57 + #define VPFE_HD_POL_SHIFT 3 58 + #define VPFE_VD_POL_MASK 1 59 + #define VPFE_VD_POL_SHIFT 2 60 + #define VPFE_HSIZE_OFF_MASK 0xffffffe0 61 + #define VPFE_32BYTE_ALIGN_VAL 31 62 + #define VPFE_FRM_FMT_MASK 0x1 63 + #define VPFE_FRM_FMT_SHIFT 7 64 + #define VPFE_DATA_SZ_MASK 7 65 + #define VPFE_DATA_SZ_SHIFT 8 66 + #define VPFE_PIX_FMT_MASK 3 67 + #define VPFE_PIX_FMT_SHIFT 12 68 + #define VPFE_VP2SDR_DISABLE 0xfffbffff 69 + #define VPFE_WEN_ENABLE (1 << 17) 70 + #define VPFE_SDR2RSZ_DISABLE 0xfff7ffff 71 + #define VPFE_VDHDEN_ENABLE (1 << 16) 72 + #define VPFE_LPF_ENABLE (1 << 14) 73 + #define VPFE_ALAW_ENABLE (1 << 3) 74 + #define VPFE_ALAW_GAMMA_WD_MASK 7 75 + #define VPFE_BLK_CLAMP_ENABLE (1 << 31) 76 + #define VPFE_BLK_SGAIN_MASK 0x1f 77 + #define VPFE_BLK_ST_PXL_MASK 0x7fff 78 + #define VPFE_BLK_ST_PXL_SHIFT 10 79 + #define VPFE_BLK_SAMPLE_LN_MASK 7 80 + #define VPFE_BLK_SAMPLE_LN_SHIFT 28 81 + #define VPFE_BLK_SAMPLE_LINE_MASK 7 82 + #define VPFE_BLK_SAMPLE_LINE_SHIFT 25 83 + #define VPFE_BLK_DC_SUB_MASK 0x03fff 84 + #define VPFE_BLK_COMP_MASK 0xff 85 + #define VPFE_BLK_COMP_GB_COMP_SHIFT 8 86 + #define VPFE_BLK_COMP_GR_COMP_SHIFT 16 87 + #define VPFE_BLK_COMP_R_COMP_SHIFT 24 88 + #define VPFE_LATCH_ON_VSYNC_DISABLE (1 << 15) 89 + #define VPFE_DATA_PACK_ENABLE (1 << 11) 90 + #define VPFE_HORZ_INFO_SPH_SHIFT 16 91 + #define VPFE_VERT_START_SLV0_SHIFT 16 92 + #define VPFE_VDINT_VDINT0_SHIFT 16 93 + #define VPFE_VDINT_VDINT1_MASK 0xffff 94 + #define VPFE_PPC_RAW 1 95 + #define VPFE_DCSUB_DEFAULT_VAL 0 96 + #define VPFE_CLAMP_DEFAULT_VAL 0 97 + #define VPFE_COLPTN_VAL 0xbb11bb11 98 + #define VPFE_TWO_BYTES_PER_PIXEL 2 99 + #define VPFE_INTERLACED_IMAGE_INVERT 0x4b6d 100 + #define VPFE_INTERLACED_NO_IMAGE_INVERT 0x0249 101 + #define VPFE_PROGRESSIVE_IMAGE_INVERT 0x4000 102 + #define VPFE_PROGRESSIVE_NO_IMAGE_INVERT 0 103 + #define VPFE_INTERLACED_HEIGHT_SHIFT 1 104 + #define VPFE_SYN_MODE_INPMOD_SHIFT 12 105 + #define VPFE_SYN_MODE_INPMOD_MASK 3 106 + #define VPFE_SYN_MODE_8BITS (7 << 8) 107 + #define VPFE_SYN_MODE_10BITS (6 << 8) 108 + #define VPFE_SYN_MODE_11BITS (5 << 8) 109 + #define VPFE_SYN_MODE_12BITS (4 << 8) 110 + #define VPFE_SYN_MODE_13BITS (3 << 8) 111 + #define VPFE_SYN_MODE_14BITS (2 << 8) 112 + #define VPFE_SYN_MODE_15BITS (1 << 8) 113 + #define VPFE_SYN_MODE_16BITS (0 << 8) 114 + #define VPFE_SYN_FLDMODE_MASK 1 115 + #define VPFE_SYN_FLDMODE_SHIFT 7 116 + #define VPFE_REC656IF_BT656_EN 3 117 + #define VPFE_SYN_MODE_VD_POL_NEGATIVE (1 << 2) 118 + #define VPFE_CCDCFG_Y8POS_SHIFT 11 119 + #define VPFE_CCDCFG_BW656_10BIT (1 << 5) 120 + #define VPFE_SDOFST_FIELD_INTERLEAVED 0x249 121 + #define VPFE_NO_CULLING 0xffff00ff 122 + #define VPFE_VDINT0 (1 << 0) 123 + #define VPFE_VDINT1 (1 << 1) 124 + #define VPFE_VDINT2 (1 << 2) 125 + #define VPFE_DMA_CNTL_OVERFLOW (1 << 31) 126 + 127 + #define VPFE_CONFIG_PCLK_INV_SHIFT 0 128 + #define VPFE_CONFIG_PCLK_INV_MASK 1 129 + #define VPFE_CONFIG_PCLK_INV_NOT_INV 0 130 + #define VPFE_CONFIG_PCLK_INV_INV 1 131 + #define VPFE_CONFIG_EN_SHIFT 1 132 + #define VPFE_CONFIG_EN_MASK 2 133 + #define VPFE_CONFIG_EN_DISABLE 0 134 + #define VPFE_CONFIG_EN_ENABLE 1 135 + #define VPFE_CONFIG_ST_SHIFT 2 136 + #define VPFE_CONFIG_ST_MASK 4 137 + #define VPFE_CONFIG_ST_OCP_ACTIVE 0 138 + #define VPFE_CONFIG_ST_OCP_STANDBY 1 139 + 140 + #endif /* AM437X_VPFE_REGS_H */
+1
include/uapi/linux/Kbuild
··· 35 35 header-y += affs_hardblocks.h 36 36 header-y += agpgart.h 37 37 header-y += aio_abi.h 38 + header-y += am437x-vpfe.h 38 39 header-y += apm_bios.h 39 40 header-y += arcfb.h 40 41 header-y += atalk.h
+122
include/uapi/linux/am437x-vpfe.h
··· 1 + /* 2 + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. 3 + * 4 + * Benoit Parrot <bparrot@ti.com> 5 + * Lad, Prabhakar <prabhakar.csengg@gmail.com> 6 + * 7 + * This program is free software; you may redistribute it and/or modify 8 + * it under the terms of the GNU General Public License as published by 9 + * the Free Software Foundation; version 2 of the License. 10 + * 11 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 12 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 13 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 15 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 16 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 + * SOFTWARE. 19 + */ 20 + 21 + #ifndef AM437X_VPFE_USER_H 22 + #define AM437X_VPFE_USER_H 23 + 24 + enum vpfe_ccdc_data_size { 25 + VPFE_CCDC_DATA_16BITS = 0, 26 + VPFE_CCDC_DATA_15BITS, 27 + VPFE_CCDC_DATA_14BITS, 28 + VPFE_CCDC_DATA_13BITS, 29 + VPFE_CCDC_DATA_12BITS, 30 + VPFE_CCDC_DATA_11BITS, 31 + VPFE_CCDC_DATA_10BITS, 32 + VPFE_CCDC_DATA_8BITS, 33 + }; 34 + 35 + /* enum for No of pixel per line to be avg. in Black Clamping*/ 36 + enum vpfe_ccdc_sample_length { 37 + VPFE_CCDC_SAMPLE_1PIXELS = 0, 38 + VPFE_CCDC_SAMPLE_2PIXELS, 39 + VPFE_CCDC_SAMPLE_4PIXELS, 40 + VPFE_CCDC_SAMPLE_8PIXELS, 41 + VPFE_CCDC_SAMPLE_16PIXELS, 42 + }; 43 + 44 + /* enum for No of lines in Black Clamping */ 45 + enum vpfe_ccdc_sample_line { 46 + VPFE_CCDC_SAMPLE_1LINES = 0, 47 + VPFE_CCDC_SAMPLE_2LINES, 48 + VPFE_CCDC_SAMPLE_4LINES, 49 + VPFE_CCDC_SAMPLE_8LINES, 50 + VPFE_CCDC_SAMPLE_16LINES, 51 + }; 52 + 53 + /* enum for Alaw gamma width */ 54 + enum vpfe_ccdc_gamma_width { 55 + VPFE_CCDC_GAMMA_BITS_15_6 = 0, /* use bits 15-6 for gamma */ 56 + VPFE_CCDC_GAMMA_BITS_14_5, 57 + VPFE_CCDC_GAMMA_BITS_13_4, 58 + VPFE_CCDC_GAMMA_BITS_12_3, 59 + VPFE_CCDC_GAMMA_BITS_11_2, 60 + VPFE_CCDC_GAMMA_BITS_10_1, 61 + VPFE_CCDC_GAMMA_BITS_09_0, /* use bits 9-0 for gamma */ 62 + }; 63 + 64 + /* structure for ALaw */ 65 + struct vpfe_ccdc_a_law { 66 + /* Enable/disable A-Law */ 67 + unsigned char enable; 68 + /* Gamma Width Input */ 69 + enum vpfe_ccdc_gamma_width gamma_wd; 70 + }; 71 + 72 + /* structure for Black Clamping */ 73 + struct vpfe_ccdc_black_clamp { 74 + unsigned char enable; 75 + /* only if bClampEnable is TRUE */ 76 + enum vpfe_ccdc_sample_length sample_pixel; 77 + /* only if bClampEnable is TRUE */ 78 + enum vpfe_ccdc_sample_line sample_ln; 79 + /* only if bClampEnable is TRUE */ 80 + unsigned short start_pixel; 81 + /* only if bClampEnable is TRUE */ 82 + unsigned short sgain; 83 + /* only if bClampEnable is FALSE */ 84 + unsigned short dc_sub; 85 + }; 86 + 87 + /* structure for Black Level Compensation */ 88 + struct vpfe_ccdc_black_compensation { 89 + /* Constant value to subtract from Red component */ 90 + char r; 91 + /* Constant value to subtract from Gr component */ 92 + char gr; 93 + /* Constant value to subtract from Blue component */ 94 + char b; 95 + /* Constant value to subtract from Gb component */ 96 + char gb; 97 + }; 98 + 99 + /* Structure for CCDC configuration parameters for raw capture mode passed 100 + * by application 101 + */ 102 + struct vpfe_ccdc_config_params_raw { 103 + /* data size value from 8 to 16 bits */ 104 + enum vpfe_ccdc_data_size data_sz; 105 + /* Structure for Optional A-Law */ 106 + struct vpfe_ccdc_a_law alaw; 107 + /* Structure for Optical Black Clamp */ 108 + struct vpfe_ccdc_black_clamp blk_clamp; 109 + /* Structure for Black Compensation */ 110 + struct vpfe_ccdc_black_compensation blk_comp; 111 + }; 112 + 113 + /* 114 + * Private IOCTL 115 + * VIDIOC_AM437X_CCDC_CFG - Set CCDC configuration for raw capture 116 + * This is an experimental ioctl that will change in future kernels. So use 117 + * this ioctl with care ! 118 + **/ 119 + #define VIDIOC_AM437X_CCDC_CFG \ 120 + _IOW('V', BASE_VIDIOC_PRIVATE + 1, void *) 121 + 122 + #endif /* AM437X_VPFE_USER_H */