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

Configure Feed

Select the types of activity you want to include in your feed.

at v4.15 889 lines 27 kB view raw
1/* 2 * Copyright (C) 2006-2009 Texas Instruments Inc 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * CCDC hardware module for DM6446 15 * ------------------------------ 16 * 17 * This module is for configuring CCD controller of DM6446 VPFE to capture 18 * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules 19 * such as Defect Pixel Correction, Color Space Conversion etc to 20 * pre-process the Raw Bayer RGB data, before writing it to SDRAM. 21 * This file is named DM644x so that other variants such DM6443 22 * may be supported using the same module. 23 * 24 * TODO: Test Raw bayer parameter settings and bayer capture 25 * Split module parameter structure to module specific ioctl structs 26 * investigate if enum used for user space type definition 27 * to be replaced by #defines or integer 28 */ 29#include <linux/platform_device.h> 30#include <linux/uaccess.h> 31#include <linux/videodev2.h> 32#include <linux/gfp.h> 33#include <linux/err.h> 34#include <linux/module.h> 35 36#include <media/davinci/dm644x_ccdc.h> 37#include <media/davinci/vpss.h> 38 39#include "dm644x_ccdc_regs.h" 40#include "ccdc_hw_device.h" 41 42MODULE_LICENSE("GPL"); 43MODULE_DESCRIPTION("CCDC Driver for DM6446"); 44MODULE_AUTHOR("Texas Instruments"); 45 46static struct ccdc_oper_config { 47 struct device *dev; 48 /* CCDC interface type */ 49 enum vpfe_hw_if_type if_type; 50 /* Raw Bayer configuration */ 51 struct ccdc_params_raw bayer; 52 /* YCbCr configuration */ 53 struct ccdc_params_ycbcr ycbcr; 54 /* ccdc base address */ 55 void __iomem *base_addr; 56} ccdc_cfg = { 57 /* Raw configurations */ 58 .bayer = { 59 .pix_fmt = CCDC_PIXFMT_RAW, 60 .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, 61 .win = CCDC_WIN_VGA, 62 .fid_pol = VPFE_PINPOL_POSITIVE, 63 .vd_pol = VPFE_PINPOL_POSITIVE, 64 .hd_pol = VPFE_PINPOL_POSITIVE, 65 .config_params = { 66 .data_sz = CCDC_DATA_10BITS, 67 }, 68 }, 69 .ycbcr = { 70 .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, 71 .frm_fmt = CCDC_FRMFMT_INTERLACED, 72 .win = CCDC_WIN_PAL, 73 .fid_pol = VPFE_PINPOL_POSITIVE, 74 .vd_pol = VPFE_PINPOL_POSITIVE, 75 .hd_pol = VPFE_PINPOL_POSITIVE, 76 .bt656_enable = 1, 77 .pix_order = CCDC_PIXORDER_CBYCRY, 78 .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED 79 }, 80}; 81 82#define CCDC_MAX_RAW_YUV_FORMATS 2 83 84/* Raw Bayer formats */ 85static u32 ccdc_raw_bayer_pix_formats[] = 86 {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; 87 88/* Raw YUV formats */ 89static u32 ccdc_raw_yuv_pix_formats[] = 90 {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; 91 92/* CCDC Save/Restore context */ 93static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)]; 94 95/* register access routines */ 96static inline u32 regr(u32 offset) 97{ 98 return __raw_readl(ccdc_cfg.base_addr + offset); 99} 100 101static inline void regw(u32 val, u32 offset) 102{ 103 __raw_writel(val, ccdc_cfg.base_addr + offset); 104} 105 106static void ccdc_enable(int flag) 107{ 108 regw(flag, CCDC_PCR); 109} 110 111static void ccdc_enable_vport(int flag) 112{ 113 if (flag) 114 /* enable video port */ 115 regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG); 116 else 117 regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG); 118} 119 120/* 121 * ccdc_setwin() 122 * This function will configure the window size 123 * to be capture in CCDC reg 124 */ 125static void ccdc_setwin(struct v4l2_rect *image_win, 126 enum ccdc_frmfmt frm_fmt, 127 int ppc) 128{ 129 int horz_start, horz_nr_pixels; 130 int vert_start, vert_nr_lines; 131 int val = 0, mid_img = 0; 132 133 dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); 134 /* 135 * ppc - per pixel count. indicates how many pixels per cell 136 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. 137 * raw capture this is 1 138 */ 139 horz_start = image_win->left << (ppc - 1); 140 horz_nr_pixels = (image_win->width << (ppc - 1)) - 1; 141 regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels, 142 CCDC_HORZ_INFO); 143 144 vert_start = image_win->top; 145 146 if (frm_fmt == CCDC_FRMFMT_INTERLACED) { 147 vert_nr_lines = (image_win->height >> 1) - 1; 148 vert_start >>= 1; 149 /* Since first line doesn't have any data */ 150 vert_start += 1; 151 /* configure VDINT0 */ 152 val = (vert_start << CCDC_VDINT_VDINT0_SHIFT); 153 regw(val, CCDC_VDINT); 154 155 } else { 156 /* Since first line doesn't have any data */ 157 vert_start += 1; 158 vert_nr_lines = image_win->height - 1; 159 /* 160 * configure VDINT0 and VDINT1. VDINT1 will be at half 161 * of image height 162 */ 163 mid_img = vert_start + (image_win->height / 2); 164 val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) | 165 (mid_img & CCDC_VDINT_VDINT1_MASK); 166 regw(val, CCDC_VDINT); 167 168 } 169 regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, 170 CCDC_VERT_START); 171 regw(vert_nr_lines, CCDC_VERT_LINES); 172 dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); 173} 174 175static void ccdc_readregs(void) 176{ 177 unsigned int val = 0; 178 179 val = regr(CCDC_ALAW); 180 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val); 181 val = regr(CCDC_CLAMP); 182 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val); 183 val = regr(CCDC_DCSUB); 184 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val); 185 val = regr(CCDC_BLKCMP); 186 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val); 187 val = regr(CCDC_FPC_ADDR); 188 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val); 189 val = regr(CCDC_FPC); 190 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val); 191 val = regr(CCDC_FMTCFG); 192 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val); 193 val = regr(CCDC_COLPTN); 194 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val); 195 val = regr(CCDC_FMT_HORZ); 196 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val); 197 val = regr(CCDC_FMT_VERT); 198 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val); 199 val = regr(CCDC_HSIZE_OFF); 200 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val); 201 val = regr(CCDC_SDOFST); 202 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val); 203 val = regr(CCDC_VP_OUT); 204 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val); 205 val = regr(CCDC_SYN_MODE); 206 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val); 207 val = regr(CCDC_HORZ_INFO); 208 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val); 209 val = regr(CCDC_VERT_START); 210 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val); 211 val = regr(CCDC_VERT_LINES); 212 dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val); 213} 214 215static int ccdc_close(struct device *dev) 216{ 217 return 0; 218} 219 220/* 221 * ccdc_restore_defaults() 222 * This function will write defaults to all CCDC registers 223 */ 224static void ccdc_restore_defaults(void) 225{ 226 int i; 227 228 /* disable CCDC */ 229 ccdc_enable(0); 230 /* set all registers to default value */ 231 for (i = 4; i <= 0x94; i += 4) 232 regw(0, i); 233 regw(CCDC_NO_CULLING, CCDC_CULLING); 234 regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW); 235} 236 237static int ccdc_open(struct device *device) 238{ 239 ccdc_restore_defaults(); 240 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 241 ccdc_enable_vport(1); 242 return 0; 243} 244 245static void ccdc_sbl_reset(void) 246{ 247 vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O); 248} 249 250/* 251 * ccdc_config_ycbcr() 252 * This function will configure CCDC for YCbCr video capture 253 */ 254static void ccdc_config_ycbcr(void) 255{ 256 struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; 257 u32 syn_mode; 258 259 dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); 260 /* 261 * first restore the CCDC registers to default values 262 * This is important since we assume default values to be set in 263 * a lot of registers that we didn't touch 264 */ 265 ccdc_restore_defaults(); 266 267 /* 268 * configure pixel format, frame format, configure video frame 269 * format, enable output to SDRAM, enable internal timing generator 270 * and 8bit pack mode 271 */ 272 syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) << 273 CCDC_SYN_MODE_INPMOD_SHIFT) | 274 ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) << 275 CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE | 276 CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE); 277 278 /* setup BT.656 sync mode */ 279 if (params->bt656_enable) { 280 regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF); 281 282 /* 283 * configure the FID, VD, HD pin polarity, 284 * fld,hd pol positive, vd negative, 8-bit data 285 */ 286 syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE; 287 if (ccdc_cfg.if_type == VPFE_BT656_10BIT) 288 syn_mode |= CCDC_SYN_MODE_10BITS; 289 else 290 syn_mode |= CCDC_SYN_MODE_8BITS; 291 } else { 292 /* y/c external sync mode */ 293 syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) << 294 CCDC_FID_POL_SHIFT) | 295 ((params->hd_pol & CCDC_HD_POL_MASK) << 296 CCDC_HD_POL_SHIFT) | 297 ((params->vd_pol & CCDC_VD_POL_MASK) << 298 CCDC_VD_POL_SHIFT)); 299 } 300 regw(syn_mode, CCDC_SYN_MODE); 301 302 /* configure video window */ 303 ccdc_setwin(&params->win, params->frm_fmt, 2); 304 305 /* 306 * configure the order of y cb cr in SDRAM, and disable latch 307 * internal register on vsync 308 */ 309 if (ccdc_cfg.if_type == VPFE_BT656_10BIT) 310 regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | 311 CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT, 312 CCDC_CCDCFG); 313 else 314 regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | 315 CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); 316 317 /* 318 * configure the horizontal line offset. This should be a 319 * on 32 byte boundary. So clear LSB 5 bits 320 */ 321 regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF); 322 323 /* configure the memory line offset */ 324 if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) 325 /* two fields are interleaved in memory */ 326 regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST); 327 328 ccdc_sbl_reset(); 329 dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); 330} 331 332static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) 333{ 334 u32 val; 335 336 if (!bclamp->enable) { 337 /* configure DCSub */ 338 val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK; 339 regw(val, CCDC_DCSUB); 340 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val); 341 regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP); 342 dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n"); 343 return; 344 } 345 /* 346 * Configure gain, Start pixel, No of line to be avg, 347 * No of pixel/line to be avg, & Enable the Black clamping 348 */ 349 val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) | 350 ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) << 351 CCDC_BLK_ST_PXL_SHIFT) | 352 ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) << 353 CCDC_BLK_SAMPLE_LINE_SHIFT) | 354 ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << 355 CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE); 356 regw(val, CCDC_CLAMP); 357 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val); 358 /* If Black clamping is enable then make dcsub 0 */ 359 regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB); 360 dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n"); 361} 362 363static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) 364{ 365 u32 val; 366 367 val = ((bcomp->b & CCDC_BLK_COMP_MASK) | 368 ((bcomp->gb & CCDC_BLK_COMP_MASK) << 369 CCDC_BLK_COMP_GB_COMP_SHIFT) | 370 ((bcomp->gr & CCDC_BLK_COMP_MASK) << 371 CCDC_BLK_COMP_GR_COMP_SHIFT) | 372 ((bcomp->r & CCDC_BLK_COMP_MASK) << 373 CCDC_BLK_COMP_R_COMP_SHIFT)); 374 regw(val, CCDC_BLKCMP); 375} 376 377/* 378 * ccdc_config_raw() 379 * This function will configure CCDC for Raw capture mode 380 */ 381static void ccdc_config_raw(void) 382{ 383 struct ccdc_params_raw *params = &ccdc_cfg.bayer; 384 struct ccdc_config_params_raw *config_params = 385 &ccdc_cfg.bayer.config_params; 386 unsigned int syn_mode = 0; 387 unsigned int val; 388 389 dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); 390 391 /* Reset CCDC */ 392 ccdc_restore_defaults(); 393 394 /* Disable latching function registers on VSYNC */ 395 regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); 396 397 /* 398 * Configure the vertical sync polarity(SYN_MODE.VDPOL), 399 * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity 400 * (SYN_MODE.FLDPOL), frame format(progressive or interlace), 401 * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output 402 * SDRAM, enable internal timing generator 403 */ 404 syn_mode = 405 (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | 406 ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | 407 ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | 408 ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | 409 ((config_params->data_sz & CCDC_DATA_SZ_MASK) << 410 CCDC_DATA_SZ_SHIFT) | 411 ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) | 412 CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE); 413 414 /* Enable and configure aLaw register if needed */ 415 if (config_params->alaw.enable) { 416 val = ((config_params->alaw.gamma_wd & 417 CCDC_ALAW_GAMMA_WD_MASK) | CCDC_ALAW_ENABLE); 418 regw(val, CCDC_ALAW); 419 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); 420 } 421 422 /* Configure video window */ 423 ccdc_setwin(&params->win, params->frm_fmt, CCDC_PPC_RAW); 424 425 /* Configure Black Clamp */ 426 ccdc_config_black_clamp(&config_params->blk_clamp); 427 428 /* Configure Black level compensation */ 429 ccdc_config_black_compense(&config_params->blk_comp); 430 431 /* If data size is 8 bit then pack the data */ 432 if ((config_params->data_sz == CCDC_DATA_8BITS) || 433 config_params->alaw.enable) 434 syn_mode |= CCDC_DATA_PACK_ENABLE; 435 436 /* disable video port */ 437 val = CCDC_DISABLE_VIDEO_PORT; 438 439 if (config_params->data_sz == CCDC_DATA_8BITS) 440 val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK) 441 << CCDC_FMTCFG_VPIN_SHIFT; 442 else 443 val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK) 444 << CCDC_FMTCFG_VPIN_SHIFT; 445 /* Write value in FMTCFG */ 446 regw(val, CCDC_FMTCFG); 447 448 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val); 449 /* Configure the color pattern according to mt9t001 sensor */ 450 regw(CCDC_COLPTN_VAL, CCDC_COLPTN); 451 452 dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); 453 /* 454 * Configure Data formatter(Video port) pixel selection 455 * (FMT_HORZ, FMT_VERT) 456 */ 457 val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) << 458 CCDC_FMT_HORZ_FMTSPH_SHIFT) | 459 (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK); 460 regw(val, CCDC_FMT_HORZ); 461 462 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val); 463 val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK) 464 << CCDC_FMT_VERT_FMTSLV_SHIFT; 465 if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) 466 val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK; 467 else 468 val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK; 469 470 dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n", 471 params->win.height); 472 regw(val, CCDC_FMT_VERT); 473 474 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val); 475 476 dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)..."); 477 478 /* 479 * Configure Horizontal offset register. If pack 8 is enabled then 480 * 1 pixel will take 1 byte 481 */ 482 if ((config_params->data_sz == CCDC_DATA_8BITS) || 483 config_params->alaw.enable) 484 regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) & 485 CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF); 486 else 487 /* else one pixel will take 2 byte */ 488 regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) + 489 CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK, 490 CCDC_HSIZE_OFF); 491 492 /* Set value for SDOFST */ 493 if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { 494 if (params->image_invert_enable) { 495 /* For intelace inverse mode */ 496 regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST); 497 dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n"); 498 } 499 500 else { 501 /* For intelace non inverse mode */ 502 regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST); 503 dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n"); 504 } 505 } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { 506 regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST); 507 dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n"); 508 } 509 510 /* 511 * Configure video port pixel selection (VPOUT) 512 * Here -1 is to make the height value less than FMT_VERT.FMTLNV 513 */ 514 if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) 515 val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) 516 << CCDC_VP_OUT_VERT_NUM_SHIFT; 517 else 518 val = 519 ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) - 520 1) & CCDC_VP_OUT_VERT_NUM_MASK)) << 521 CCDC_VP_OUT_VERT_NUM_SHIFT; 522 523 val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK) 524 << CCDC_VP_OUT_HORZ_NUM_SHIFT; 525 val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK; 526 regw(val, CCDC_VP_OUT); 527 528 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val); 529 regw(syn_mode, CCDC_SYN_MODE); 530 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); 531 532 ccdc_sbl_reset(); 533 dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); 534 ccdc_readregs(); 535} 536 537static int ccdc_configure(void) 538{ 539 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 540 ccdc_config_raw(); 541 else 542 ccdc_config_ycbcr(); 543 return 0; 544} 545 546static int ccdc_set_buftype(enum ccdc_buftype buf_type) 547{ 548 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 549 ccdc_cfg.bayer.buf_type = buf_type; 550 else 551 ccdc_cfg.ycbcr.buf_type = buf_type; 552 return 0; 553} 554 555static enum ccdc_buftype ccdc_get_buftype(void) 556{ 557 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 558 return ccdc_cfg.bayer.buf_type; 559 return ccdc_cfg.ycbcr.buf_type; 560} 561 562static int ccdc_enum_pix(u32 *pix, int i) 563{ 564 int ret = -EINVAL; 565 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { 566 if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { 567 *pix = ccdc_raw_bayer_pix_formats[i]; 568 ret = 0; 569 } 570 } else { 571 if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { 572 *pix = ccdc_raw_yuv_pix_formats[i]; 573 ret = 0; 574 } 575 } 576 return ret; 577} 578 579static int ccdc_set_pixel_format(u32 pixfmt) 580{ 581 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { 582 ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; 583 if (pixfmt == V4L2_PIX_FMT_SBGGR8) 584 ccdc_cfg.bayer.config_params.alaw.enable = 1; 585 else if (pixfmt != V4L2_PIX_FMT_SBGGR16) 586 return -EINVAL; 587 } else { 588 if (pixfmt == V4L2_PIX_FMT_YUYV) 589 ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; 590 else if (pixfmt == V4L2_PIX_FMT_UYVY) 591 ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; 592 else 593 return -EINVAL; 594 } 595 return 0; 596} 597 598static u32 ccdc_get_pixel_format(void) 599{ 600 struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; 601 u32 pixfmt; 602 603 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 604 if (alaw->enable) 605 pixfmt = V4L2_PIX_FMT_SBGGR8; 606 else 607 pixfmt = V4L2_PIX_FMT_SBGGR16; 608 else { 609 if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) 610 pixfmt = V4L2_PIX_FMT_YUYV; 611 else 612 pixfmt = V4L2_PIX_FMT_UYVY; 613 } 614 return pixfmt; 615} 616 617static int ccdc_set_image_window(struct v4l2_rect *win) 618{ 619 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 620 ccdc_cfg.bayer.win = *win; 621 else 622 ccdc_cfg.ycbcr.win = *win; 623 return 0; 624} 625 626static void ccdc_get_image_window(struct v4l2_rect *win) 627{ 628 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 629 *win = ccdc_cfg.bayer.win; 630 else 631 *win = ccdc_cfg.ycbcr.win; 632} 633 634static unsigned int ccdc_get_line_length(void) 635{ 636 struct ccdc_config_params_raw *config_params = 637 &ccdc_cfg.bayer.config_params; 638 unsigned int len; 639 640 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { 641 if ((config_params->alaw.enable) || 642 (config_params->data_sz == CCDC_DATA_8BITS)) 643 len = ccdc_cfg.bayer.win.width; 644 else 645 len = ccdc_cfg.bayer.win.width * 2; 646 } else 647 len = ccdc_cfg.ycbcr.win.width * 2; 648 return ALIGN(len, 32); 649} 650 651static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) 652{ 653 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 654 ccdc_cfg.bayer.frm_fmt = frm_fmt; 655 else 656 ccdc_cfg.ycbcr.frm_fmt = frm_fmt; 657 return 0; 658} 659 660static enum ccdc_frmfmt ccdc_get_frame_format(void) 661{ 662 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 663 return ccdc_cfg.bayer.frm_fmt; 664 else 665 return ccdc_cfg.ycbcr.frm_fmt; 666} 667 668static int ccdc_getfid(void) 669{ 670 return (regr(CCDC_SYN_MODE) >> 15) & 1; 671} 672 673/* misc operations */ 674static inline void ccdc_setfbaddr(unsigned long addr) 675{ 676 regw(addr & 0xffffffe0, CCDC_SDR_ADDR); 677} 678 679static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) 680{ 681 ccdc_cfg.if_type = params->if_type; 682 683 switch (params->if_type) { 684 case VPFE_BT656: 685 case VPFE_YCBCR_SYNC_16: 686 case VPFE_YCBCR_SYNC_8: 687 case VPFE_BT656_10BIT: 688 ccdc_cfg.ycbcr.vd_pol = params->vdpol; 689 ccdc_cfg.ycbcr.hd_pol = params->hdpol; 690 break; 691 default: 692 /* TODO add support for raw bayer here */ 693 return -EINVAL; 694 } 695 return 0; 696} 697 698static void ccdc_save_context(void) 699{ 700 ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR); 701 ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE); 702 ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID); 703 ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES); 704 ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO); 705 ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START); 706 ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES); 707 ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING); 708 ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF); 709 ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST); 710 ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR); 711 ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP); 712 ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB); 713 ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN); 714 ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP); 715 ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC); 716 ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR); 717 ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT); 718 ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW); 719 ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF); 720 ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG); 721 ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG); 722 ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ); 723 ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT); 724 ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0); 725 ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1); 726 ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2); 727 ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3); 728 ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4); 729 ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5); 730 ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6); 731 ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7); 732 ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0); 733 ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1); 734 ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0); 735 ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1); 736 ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT); 737} 738 739static void ccdc_restore_context(void) 740{ 741 regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE); 742 regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID); 743 regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES); 744 regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO); 745 regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START); 746 regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES); 747 regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING); 748 regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF); 749 regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST); 750 regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR); 751 regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP); 752 regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB); 753 regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN); 754 regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP); 755 regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC); 756 regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR); 757 regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT); 758 regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW); 759 regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF); 760 regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG); 761 regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG); 762 regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ); 763 regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT); 764 regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0); 765 regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1); 766 regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2); 767 regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3); 768 regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4); 769 regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5); 770 regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6); 771 regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7); 772 regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0); 773 regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1); 774 regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0); 775 regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1); 776 regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT); 777 regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR); 778} 779static const struct ccdc_hw_device ccdc_hw_dev = { 780 .name = "DM6446 CCDC", 781 .owner = THIS_MODULE, 782 .hw_ops = { 783 .open = ccdc_open, 784 .close = ccdc_close, 785 .reset = ccdc_sbl_reset, 786 .enable = ccdc_enable, 787 .set_hw_if_params = ccdc_set_hw_if_params, 788 .configure = ccdc_configure, 789 .set_buftype = ccdc_set_buftype, 790 .get_buftype = ccdc_get_buftype, 791 .enum_pix = ccdc_enum_pix, 792 .set_pixel_format = ccdc_set_pixel_format, 793 .get_pixel_format = ccdc_get_pixel_format, 794 .set_frame_format = ccdc_set_frame_format, 795 .get_frame_format = ccdc_get_frame_format, 796 .set_image_window = ccdc_set_image_window, 797 .get_image_window = ccdc_get_image_window, 798 .get_line_length = ccdc_get_line_length, 799 .setfbaddr = ccdc_setfbaddr, 800 .getfid = ccdc_getfid, 801 }, 802}; 803 804static int dm644x_ccdc_probe(struct platform_device *pdev) 805{ 806 struct resource *res; 807 int status = 0; 808 809 /* 810 * first try to register with vpfe. If not correct platform, then we 811 * don't have to iomap 812 */ 813 status = vpfe_register_ccdc_device(&ccdc_hw_dev); 814 if (status < 0) 815 return status; 816 817 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 818 if (!res) { 819 status = -ENODEV; 820 goto fail_nores; 821 } 822 823 res = request_mem_region(res->start, resource_size(res), res->name); 824 if (!res) { 825 status = -EBUSY; 826 goto fail_nores; 827 } 828 829 ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); 830 if (!ccdc_cfg.base_addr) { 831 status = -ENOMEM; 832 goto fail_nomem; 833 } 834 835 ccdc_cfg.dev = &pdev->dev; 836 printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); 837 return 0; 838fail_nomem: 839 release_mem_region(res->start, resource_size(res)); 840fail_nores: 841 vpfe_unregister_ccdc_device(&ccdc_hw_dev); 842 return status; 843} 844 845static int dm644x_ccdc_remove(struct platform_device *pdev) 846{ 847 struct resource *res; 848 849 iounmap(ccdc_cfg.base_addr); 850 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 851 if (res) 852 release_mem_region(res->start, resource_size(res)); 853 vpfe_unregister_ccdc_device(&ccdc_hw_dev); 854 return 0; 855} 856 857static int dm644x_ccdc_suspend(struct device *dev) 858{ 859 /* Save CCDC context */ 860 ccdc_save_context(); 861 /* Disable CCDC */ 862 ccdc_enable(0); 863 864 return 0; 865} 866 867static int dm644x_ccdc_resume(struct device *dev) 868{ 869 /* Restore CCDC context */ 870 ccdc_restore_context(); 871 872 return 0; 873} 874 875static const struct dev_pm_ops dm644x_ccdc_pm_ops = { 876 .suspend = dm644x_ccdc_suspend, 877 .resume = dm644x_ccdc_resume, 878}; 879 880static struct platform_driver dm644x_ccdc_driver = { 881 .driver = { 882 .name = "dm644x_ccdc", 883 .pm = &dm644x_ccdc_pm_ops, 884 }, 885 .remove = dm644x_ccdc_remove, 886 .probe = dm644x_ccdc_probe, 887}; 888 889module_platform_driver(dm644x_ccdc_driver);