1/* 2 * Copyright (C) 2005-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 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * 18 * CCDC hardware module for DM355 19 * ------------------------------ 20 * 21 * This module is for configuring DM355 CCD controller of VPFE to capture 22 * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules 23 * such as Defect Pixel Correction, Color Space Conversion etc to 24 * pre-process the Bayer RGB data, before writing it to SDRAM. This 25 * module also allows application to configure individual 26 * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. 27 * To do so, application include dm355_ccdc.h and vpfe_capture.h header 28 * files. The setparams() API is called by vpfe_capture driver 29 * to configure module parameters 30 * 31 * TODO: 1) Raw bayer parameter settings and bayer capture 32 * 2) Split module parameter structure to module specific ioctl structs 33 * 3) add support for lense shading correction 34 * 4) investigate if enum used for user space type definition 35 * to be replaced by #defines or integer 36 */ 37#include <linux/platform_device.h> 38#include <linux/uaccess.h> 39#include <linux/videodev2.h> 40#include <linux/err.h> 41#include <linux/module.h> 42 43#include <media/davinci/dm355_ccdc.h> 44#include <media/davinci/vpss.h> 45 46#include "dm355_ccdc_regs.h" 47#include "ccdc_hw_device.h" 48 49MODULE_LICENSE("GPL"); 50MODULE_DESCRIPTION("CCDC Driver for DM355"); 51MODULE_AUTHOR("Texas Instruments"); 52 53static struct ccdc_oper_config { 54 struct device *dev; 55 /* CCDC interface type */ 56 enum vpfe_hw_if_type if_type; 57 /* Raw Bayer configuration */ 58 struct ccdc_params_raw bayer; 59 /* YCbCr configuration */ 60 struct ccdc_params_ycbcr ycbcr; 61 /* ccdc base address */ 62 void __iomem *base_addr; 63} ccdc_cfg = { 64 /* Raw configurations */ 65 .bayer = { 66 .pix_fmt = CCDC_PIXFMT_RAW, 67 .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, 68 .win = CCDC_WIN_VGA, 69 .fid_pol = VPFE_PINPOL_POSITIVE, 70 .vd_pol = VPFE_PINPOL_POSITIVE, 71 .hd_pol = VPFE_PINPOL_POSITIVE, 72 .gain = { 73 .r_ye = 256, 74 .gb_g = 256, 75 .gr_cy = 256, 76 .b_mg = 256 77 }, 78 .config_params = { 79 .datasft = 2, 80 .mfilt1 = CCDC_NO_MEDIAN_FILTER1, 81 .mfilt2 = CCDC_NO_MEDIAN_FILTER2, 82 .alaw = { 83 .gamma_wd = 2, 84 }, 85 .blk_clamp = { 86 .sample_pixel = 1, 87 .dc_sub = 25 88 }, 89 .col_pat_field0 = { 90 .olop = CCDC_GREEN_BLUE, 91 .olep = CCDC_BLUE, 92 .elop = CCDC_RED, 93 .elep = CCDC_GREEN_RED 94 }, 95 .col_pat_field1 = { 96 .olop = CCDC_GREEN_BLUE, 97 .olep = CCDC_BLUE, 98 .elop = CCDC_RED, 99 .elep = CCDC_GREEN_RED 100 }, 101 }, 102 }, 103 /* YCbCr configuration */ 104 .ycbcr = { 105 .win = CCDC_WIN_PAL, 106 .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, 107 .frm_fmt = CCDC_FRMFMT_INTERLACED, 108 .fid_pol = VPFE_PINPOL_POSITIVE, 109 .vd_pol = VPFE_PINPOL_POSITIVE, 110 .hd_pol = VPFE_PINPOL_POSITIVE, 111 .bt656_enable = 1, 112 .pix_order = CCDC_PIXORDER_CBYCRY, 113 .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED 114 }, 115}; 116 117 118/* Raw Bayer formats */ 119static u32 ccdc_raw_bayer_pix_formats[] = 120 {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; 121 122/* Raw YUV formats */ 123static u32 ccdc_raw_yuv_pix_formats[] = 124 {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; 125 126/* register access routines */ 127static inline u32 regr(u32 offset) 128{ 129 return __raw_readl(ccdc_cfg.base_addr + offset); 130} 131 132static inline void regw(u32 val, u32 offset) 133{ 134 __raw_writel(val, ccdc_cfg.base_addr + offset); 135} 136 137static void ccdc_enable(int en) 138{ 139 unsigned int temp; 140 temp = regr(SYNCEN); 141 temp &= (~CCDC_SYNCEN_VDHDEN_MASK); 142 temp |= (en & CCDC_SYNCEN_VDHDEN_MASK); 143 regw(temp, SYNCEN); 144} 145 146static void ccdc_enable_output_to_sdram(int en) 147{ 148 unsigned int temp; 149 temp = regr(SYNCEN); 150 temp &= (~(CCDC_SYNCEN_WEN_MASK)); 151 temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK); 152 regw(temp, SYNCEN); 153} 154 155static void ccdc_config_gain_offset(void) 156{ 157 /* configure gain */ 158 regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN); 159 regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN); 160 regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN); 161 regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN); 162 /* configure offset */ 163 regw(ccdc_cfg.bayer.ccdc_offset, OFFSET); 164} 165 166/* 167 * ccdc_restore_defaults() 168 * This function restore power on defaults in the ccdc registers 169 */ 170static int ccdc_restore_defaults(void) 171{ 172 int i; 173 174 dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults..."); 175 /* set all registers to zero */ 176 for (i = 0; i <= CCDC_REG_LAST; i += 4) 177 regw(0, i); 178 179 /* now override the values with power on defaults in registers */ 180 regw(MODESET_DEFAULT, MODESET); 181 /* no culling support */ 182 regw(CULH_DEFAULT, CULH); 183 regw(CULV_DEFAULT, CULV); 184 /* Set default Gain and Offset */ 185 ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT; 186 ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT; 187 ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT; 188 ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT; 189 ccdc_config_gain_offset(); 190 regw(OUTCLIP_DEFAULT, OUTCLIP); 191 regw(LSCCFG2_DEFAULT, LSCCFG2); 192 /* select ccdc input */ 193 if (vpss_select_ccdc_source(VPSS_CCDCIN)) { 194 dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source"); 195 return -EFAULT; 196 } 197 /* select ccdc clock */ 198 if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { 199 dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock"); 200 return -EFAULT; 201 } 202 dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults..."); 203 return 0; 204} 205 206static int ccdc_open(struct device *device) 207{ 208 return ccdc_restore_defaults(); 209} 210 211static int ccdc_close(struct device *device) 212{ 213 /* disable clock */ 214 vpss_enable_clock(VPSS_CCDC_CLOCK, 0); 215 /* do nothing for now */ 216 return 0; 217} 218/* 219 * ccdc_setwin() 220 * This function will configure the window size to 221 * be capture in CCDC reg. 222 */ 223static void ccdc_setwin(struct v4l2_rect *image_win, 224 enum ccdc_frmfmt frm_fmt, int ppc) 225{ 226 int horz_start, horz_nr_pixels; 227 int vert_start, vert_nr_lines; 228 int mid_img = 0; 229 230 dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); 231 232 /* 233 * ppc - per pixel count. indicates how many pixels per cell 234 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. 235 * raw capture this is 1 236 */ 237 horz_start = image_win->left << (ppc - 1); 238 horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; 239 240 /* Writing the horizontal info into the registers */ 241 regw(horz_start, SPH); 242 regw(horz_nr_pixels, NPH); 243 vert_start = image_win->top; 244 245 if (frm_fmt == CCDC_FRMFMT_INTERLACED) { 246 vert_nr_lines = (image_win->height >> 1) - 1; 247 vert_start >>= 1; 248 /* Since first line doesn't have any data */ 249 vert_start += 1; 250 /* configure VDINT0 and VDINT1 */ 251 regw(vert_start, VDINT0); 252 } else { 253 /* Since first line doesn't have any data */ 254 vert_start += 1; 255 vert_nr_lines = image_win->height - 1; 256 /* configure VDINT0 and VDINT1 */ 257 mid_img = vert_start + (image_win->height / 2); 258 regw(vert_start, VDINT0); 259 regw(mid_img, VDINT1); 260 } 261 regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0); 262 regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); 263 regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); 264 dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); 265} 266 267static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) 268{ 269 if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT || 270 ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) { 271 dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n"); 272 return -EINVAL; 273 } 274 275 if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 || 276 ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) { 277 dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n"); 278 return -EINVAL; 279 } 280 281 if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 || 282 ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) { 283 dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n"); 284 return -EINVAL; 285 } 286 287 if ((ccdcparam->med_filt_thres < 0) || 288 (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { 289 dev_dbg(ccdc_cfg.dev, 290 "Invalid value of median filter threshold\n"); 291 return -EINVAL; 292 } 293 294 if (ccdcparam->data_sz < CCDC_DATA_16BITS || 295 ccdcparam->data_sz > CCDC_DATA_8BITS) { 296 dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n"); 297 return -EINVAL; 298 } 299 300 if (ccdcparam->alaw.enable) { 301 if (ccdcparam->alaw.gamma_wd < CCDC_GAMMA_BITS_13_4 || 302 ccdcparam->alaw.gamma_wd > CCDC_GAMMA_BITS_09_0) { 303 dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n"); 304 return -EINVAL; 305 } 306 } 307 308 if (ccdcparam->blk_clamp.b_clamp_enable) { 309 if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS || 310 ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) { 311 dev_dbg(ccdc_cfg.dev, 312 "Invalid value of sample pixel\n"); 313 return -EINVAL; 314 } 315 if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES || 316 ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) { 317 dev_dbg(ccdc_cfg.dev, 318 "Invalid value of sample lines\n"); 319 return -EINVAL; 320 } 321 } 322 return 0; 323} 324 325/* Parameter operations */ 326static int ccdc_set_params(void __user *params) 327{ 328 struct ccdc_config_params_raw ccdc_raw_params; 329 int x; 330 331 /* only raw module parameters can be set through the IOCTL */ 332 if (ccdc_cfg.if_type != VPFE_RAW_BAYER) 333 return -EINVAL; 334 335 x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); 336 if (x) { 337 dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc" 338 "params, %d\n", x); 339 return -EFAULT; 340 } 341 342 if (!validate_ccdc_param(&ccdc_raw_params)) { 343 memcpy(&ccdc_cfg.bayer.config_params, 344 &ccdc_raw_params, 345 sizeof(ccdc_raw_params)); 346 return 0; 347 } 348 return -EINVAL; 349} 350 351/* This function will configure CCDC for YCbCr video capture */ 352static void ccdc_config_ycbcr(void) 353{ 354 struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; 355 u32 temp; 356 357 /* first set the CCDC power on defaults values in all registers */ 358 dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); 359 ccdc_restore_defaults(); 360 361 /* configure pixel format & video frame format */ 362 temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) << 363 CCDC_INPUT_MODE_SHIFT) | 364 ((params->frm_fmt & CCDC_FRM_FMT_MASK) << 365 CCDC_FRM_FMT_SHIFT)); 366 367 /* setup BT.656 sync mode */ 368 if (params->bt656_enable) { 369 regw(CCDC_REC656IF_BT656_EN, REC656IF); 370 /* 371 * configure the FID, VD, HD pin polarity fld,hd pol positive, 372 * vd negative, 8-bit pack mode 373 */ 374 temp |= CCDC_VD_POL_NEGATIVE; 375 } else { /* y/c external sync mode */ 376 temp |= (((params->fid_pol & CCDC_FID_POL_MASK) << 377 CCDC_FID_POL_SHIFT) | 378 ((params->hd_pol & CCDC_HD_POL_MASK) << 379 CCDC_HD_POL_SHIFT) | 380 ((params->vd_pol & CCDC_VD_POL_MASK) << 381 CCDC_VD_POL_SHIFT)); 382 } 383 384 /* pack the data to 8-bit */ 385 temp |= CCDC_DATA_PACK_ENABLE; 386 387 regw(temp, MODESET); 388 389 /* configure video window */ 390 ccdc_setwin(¶ms->win, params->frm_fmt, 2); 391 392 /* configure the order of y cb cr in SD-RAM */ 393 temp = (params->pix_order << CCDC_Y8POS_SHIFT); 394 temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC; 395 regw(temp, CCDCFG); 396 397 /* 398 * configure the horizontal line offset. This is done by rounding up 399 * width to a multiple of 16 pixels and multiply by two to account for 400 * y:cb:cr 4:2:2 data 401 */ 402 regw(((params->win.width * 2 + 31) >> 5), HSIZE); 403 404 /* configure the memory line offset */ 405 if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { 406 /* two fields are interleaved in memory */ 407 regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); 408 } 409 410 dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); 411} 412 413/* 414 * ccdc_config_black_clamp() 415 * configure parameters for Optical Black Clamp 416 */ 417static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) 418{ 419 u32 val; 420 421 if (!bclamp->b_clamp_enable) { 422 /* configure DCSub */ 423 regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB); 424 regw(0x0000, CLAMP); 425 return; 426 } 427 /* Enable the Black clamping, set sample lines and pixels */ 428 val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) | 429 ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << 430 CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE; 431 regw(val, CLAMP); 432 433 /* If Black clamping is enable then make dcsub 0 */ 434 val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK) 435 << CCDC_NUM_LINE_CALC_SHIFT; 436 regw(val, DCSUB); 437} 438 439/* 440 * ccdc_config_black_compense() 441 * configure parameters for Black Compensation 442 */ 443static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) 444{ 445 u32 val; 446 447 val = (bcomp->b & CCDC_BLK_COMP_MASK) | 448 ((bcomp->gb & CCDC_BLK_COMP_MASK) << 449 CCDC_BLK_COMP_GB_COMP_SHIFT); 450 regw(val, BLKCMP1); 451 452 val = ((bcomp->gr & CCDC_BLK_COMP_MASK) << 453 CCDC_BLK_COMP_GR_COMP_SHIFT) | 454 ((bcomp->r & CCDC_BLK_COMP_MASK) << 455 CCDC_BLK_COMP_R_COMP_SHIFT); 456 regw(val, BLKCMP0); 457} 458 459/* 460 * ccdc_write_dfc_entry() 461 * write an entry in the dfc table. 462 */ 463static int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) 464{ 465/* TODO This is to be re-visited and adjusted */ 466#define DFC_WRITE_WAIT_COUNT 1000 467 u32 val, count = DFC_WRITE_WAIT_COUNT; 468 469 regw(dfc->dft_corr_vert[index], DFCMEM0); 470 regw(dfc->dft_corr_horz[index], DFCMEM1); 471 regw(dfc->dft_corr_sub1[index], DFCMEM2); 472 regw(dfc->dft_corr_sub2[index], DFCMEM3); 473 regw(dfc->dft_corr_sub3[index], DFCMEM4); 474 /* set WR bit to write */ 475 val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK; 476 regw(val, DFCMEMCTL); 477 478 /* 479 * Assume, it is very short. If we get an error, we need to 480 * adjust this value 481 */ 482 while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK) 483 count--; 484 /* 485 * TODO We expect the count to be non-zero to be successful. Adjust 486 * the count if write requires more time 487 */ 488 489 if (count) { 490 dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n"); 491 return -1; 492 } 493 return 0; 494} 495 496/* 497 * ccdc_config_vdfc() 498 * configure parameters for Vertical Defect Correction 499 */ 500static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc) 501{ 502 u32 val; 503 int i; 504 505 /* Configure General Defect Correction. The table used is from IPIPE */ 506 val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK; 507 508 /* Configure Vertical Defect Correction if needed */ 509 if (!dfc->ver_dft_en) { 510 /* Enable only General Defect Correction */ 511 regw(val, DFCCTL); 512 return 0; 513 } 514 515 if (dfc->table_size > CCDC_DFT_TABLE_SIZE) 516 return -EINVAL; 517 518 val |= CCDC_DFCCTL_VDFC_DISABLE; 519 val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) << 520 CCDC_DFCCTL_VDFCSL_SHIFT; 521 val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) << 522 CCDC_DFCCTL_VDFCUDA_SHIFT; 523 val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) << 524 CCDC_DFCCTL_VDFLSFT_SHIFT; 525 regw(val , DFCCTL); 526 527 /* clear address ptr to offset 0 */ 528 val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT; 529 530 /* write defect table entries */ 531 for (i = 0; i < dfc->table_size; i++) { 532 /* increment address for non zero index */ 533 if (i != 0) 534 val = CCDC_DFCMEMCTL_INC_ADDR; 535 regw(val, DFCMEMCTL); 536 if (ccdc_write_dfc_entry(i, dfc) < 0) 537 return -EFAULT; 538 } 539 540 /* update saturation level and enable dfc */ 541 regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT); 542 val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK << 543 CCDC_DFCCTL_VDFCEN_SHIFT); 544 regw(val, DFCCTL); 545 return 0; 546} 547 548/* 549 * ccdc_config_csc() 550 * configure parameters for color space conversion 551 * Each register CSCM0-7 has two values in S8Q5 format. 552 */ 553static void ccdc_config_csc(struct ccdc_csc *csc) 554{ 555 u32 val1 = 0, val2; 556 int i; 557 558 if (!csc->enable) 559 return; 560 561 /* Enable the CSC sub-module */ 562 regw(CCDC_CSC_ENABLE, CSCCTL); 563 564 /* Converting the co-eff as per the format of the register */ 565 for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) { 566 if ((i % 2) == 0) { 567 /* CSCM - LSB */ 568 val1 = (csc->coeff[i].integer & 569 CCDC_CSC_COEF_INTEG_MASK) 570 << CCDC_CSC_COEF_INTEG_SHIFT; 571 /* 572 * convert decimal part to binary. Use 2 decimal 573 * precision, user values range from .00 - 0.99 574 */ 575 val1 |= (((csc->coeff[i].decimal & 576 CCDC_CSC_COEF_DECIMAL_MASK) * 577 CCDC_CSC_DEC_MAX) / 100); 578 } else { 579 580 /* CSCM - MSB */ 581 val2 = (csc->coeff[i].integer & 582 CCDC_CSC_COEF_INTEG_MASK) 583 << CCDC_CSC_COEF_INTEG_SHIFT; 584 val2 |= (((csc->coeff[i].decimal & 585 CCDC_CSC_COEF_DECIMAL_MASK) * 586 CCDC_CSC_DEC_MAX) / 100); 587 val2 <<= CCDC_CSCM_MSB_SHIFT; 588 val2 |= val1; 589 regw(val2, (CSCM0 + ((i - 1) << 1))); 590 } 591 } 592} 593 594/* 595 * ccdc_config_color_patterns() 596 * configure parameters for color patterns 597 */ 598static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, 599 struct ccdc_col_pat *pat1) 600{ 601 u32 val; 602 603 val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) | 604 (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) | 605 (pat1->elop << 12) | (pat1->elep << 14)); 606 regw(val, COLPTN); 607} 608 609/* This function will configure CCDC for Raw mode image capture */ 610static int ccdc_config_raw(void) 611{ 612 struct ccdc_params_raw *params = &ccdc_cfg.bayer; 613 struct ccdc_config_params_raw *config_params = 614 &ccdc_cfg.bayer.config_params; 615 unsigned int val; 616 617 dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); 618 619 /* restore power on defaults to register */ 620 ccdc_restore_defaults(); 621 622 /* CCDCFG register: 623 * set CCD Not to swap input since input is RAW data 624 * set FID detection function to Latch at V-Sync 625 * set WENLOG - ccdc valid area to AND 626 * set TRGSEL to WENBIT 627 * set EXTRG to DISABLE 628 * disable latching function on VSYNC - shadowed registers 629 */ 630 regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | 631 CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | 632 CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG); 633 634 /* 635 * Set VDHD direction to input, input type to raw input 636 * normal data polarity, do not use external WEN 637 */ 638 val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL | 639 CCDC_EXWEN_DISABLE); 640 641 /* 642 * Configure the vertical sync polarity (MODESET.VDPOL), horizontal 643 * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL), 644 * frame format(progressive or interlace), & pixel format (Input mode) 645 */ 646 val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | 647 ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | 648 ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | 649 ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | 650 ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT)); 651 652 /* set pack for alaw compression */ 653 if ((config_params->data_sz == CCDC_DATA_8BITS) || 654 config_params->alaw.enable) 655 val |= CCDC_DATA_PACK_ENABLE; 656 657 /* Configure for LPF */ 658 if (config_params->lpf_enable) 659 val |= (config_params->lpf_enable & CCDC_LPF_MASK) << 660 CCDC_LPF_SHIFT; 661 662 /* Configure the data shift */ 663 val |= (config_params->datasft & CCDC_DATASFT_MASK) << 664 CCDC_DATASFT_SHIFT; 665 regw(val , MODESET); 666 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val); 667 668 /* Configure the Median Filter threshold */ 669 regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); 670 671 /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */ 672 val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT | 673 CCDC_CFA_MOSAIC; 674 675 /* Enable and configure aLaw register if needed */ 676 if (config_params->alaw.enable) { 677 val |= (CCDC_ALAW_ENABLE | 678 ((config_params->alaw.gamma_wd & 679 CCDC_ALAW_GAMMA_WD_MASK) << 680 CCDC_GAMMAWD_INPUT_SHIFT)); 681 } 682 683 /* Configure Median filter1 & filter2 */ 684 val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) | 685 (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); 686 687 regw(val, GAMMAWD); 688 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val); 689 690 /* configure video window */ 691 ccdc_setwin(¶ms->win, params->frm_fmt, 1); 692 693 /* Optical Clamp Averaging */ 694 ccdc_config_black_clamp(&config_params->blk_clamp); 695 696 /* Black level compensation */ 697 ccdc_config_black_compense(&config_params->blk_comp); 698 699 /* Vertical Defect Correction if needed */ 700 if (ccdc_config_vdfc(&config_params->vertical_dft) < 0) 701 return -EFAULT; 702 703 /* color space conversion */ 704 ccdc_config_csc(&config_params->csc); 705 706 /* color pattern */ 707 ccdc_config_color_patterns(&config_params->col_pat_field0, 708 &config_params->col_pat_field1); 709 710 /* Configure the Gain & offset control */ 711 ccdc_config_gain_offset(); 712 713 dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val); 714 715 /* Configure DATAOFST register */ 716 val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << 717 CCDC_DATAOFST_H_SHIFT; 718 val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) << 719 CCDC_DATAOFST_V_SHIFT; 720 regw(val, DATAOFST); 721 722 /* configuring HSIZE register */ 723 val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) << 724 CCDC_HSIZE_FLIP_SHIFT; 725 726 /* If pack 8 is enable then 1 pixel will take 1 byte */ 727 if ((config_params->data_sz == CCDC_DATA_8BITS) || 728 config_params->alaw.enable) { 729 val |= (((params->win.width) + 31) >> 5) & 730 CCDC_HSIZE_VAL_MASK; 731 732 /* adjust to multiple of 32 */ 733 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", 734 (((params->win.width) + 31) >> 5) & 735 CCDC_HSIZE_VAL_MASK); 736 } else { 737 /* else one pixel will take 2 byte */ 738 val |= (((params->win.width * 2) + 31) >> 5) & 739 CCDC_HSIZE_VAL_MASK; 740 741 dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", 742 (((params->win.width * 2) + 31) >> 5) & 743 CCDC_HSIZE_VAL_MASK); 744 } 745 regw(val, HSIZE); 746 747 /* Configure SDOFST register */ 748 if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { 749 if (params->image_invert_enable) { 750 /* For interlace inverse mode */ 751 regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); 752 dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", 753 CCDC_SDOFST_INTERLACE_INVERSE); 754 } else { 755 /* For interlace non inverse mode */ 756 regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); 757 dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", 758 CCDC_SDOFST_INTERLACE_NORMAL); 759 } 760 } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { 761 if (params->image_invert_enable) { 762 /* For progessive inverse mode */ 763 regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); 764 dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", 765 CCDC_SDOFST_PROGRESSIVE_INVERSE); 766 } else { 767 /* For progessive non inverse mode */ 768 regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); 769 dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", 770 CCDC_SDOFST_PROGRESSIVE_NORMAL); 771 } 772 } 773 dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); 774 return 0; 775} 776 777static int ccdc_configure(void) 778{ 779 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 780 return ccdc_config_raw(); 781 else 782 ccdc_config_ycbcr(); 783 return 0; 784} 785 786static int ccdc_set_buftype(enum ccdc_buftype buf_type) 787{ 788 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 789 ccdc_cfg.bayer.buf_type = buf_type; 790 else 791 ccdc_cfg.ycbcr.buf_type = buf_type; 792 return 0; 793} 794static enum ccdc_buftype ccdc_get_buftype(void) 795{ 796 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 797 return ccdc_cfg.bayer.buf_type; 798 return ccdc_cfg.ycbcr.buf_type; 799} 800 801static int ccdc_enum_pix(u32 *pix, int i) 802{ 803 int ret = -EINVAL; 804 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { 805 if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { 806 *pix = ccdc_raw_bayer_pix_formats[i]; 807 ret = 0; 808 } 809 } else { 810 if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { 811 *pix = ccdc_raw_yuv_pix_formats[i]; 812 ret = 0; 813 } 814 } 815 return ret; 816} 817 818static int ccdc_set_pixel_format(u32 pixfmt) 819{ 820 struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; 821 822 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { 823 ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; 824 if (pixfmt == V4L2_PIX_FMT_SBGGR8) 825 alaw->enable = 1; 826 else if (pixfmt != V4L2_PIX_FMT_SBGGR16) 827 return -EINVAL; 828 } else { 829 if (pixfmt == V4L2_PIX_FMT_YUYV) 830 ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; 831 else if (pixfmt == V4L2_PIX_FMT_UYVY) 832 ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; 833 else 834 return -EINVAL; 835 } 836 return 0; 837} 838static u32 ccdc_get_pixel_format(void) 839{ 840 struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; 841 u32 pixfmt; 842 843 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 844 if (alaw->enable) 845 pixfmt = V4L2_PIX_FMT_SBGGR8; 846 else 847 pixfmt = V4L2_PIX_FMT_SBGGR16; 848 else { 849 if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) 850 pixfmt = V4L2_PIX_FMT_YUYV; 851 else 852 pixfmt = V4L2_PIX_FMT_UYVY; 853 } 854 return pixfmt; 855} 856static int ccdc_set_image_window(struct v4l2_rect *win) 857{ 858 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 859 ccdc_cfg.bayer.win = *win; 860 else 861 ccdc_cfg.ycbcr.win = *win; 862 return 0; 863} 864 865static void ccdc_get_image_window(struct v4l2_rect *win) 866{ 867 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 868 *win = ccdc_cfg.bayer.win; 869 else 870 *win = ccdc_cfg.ycbcr.win; 871} 872 873static unsigned int ccdc_get_line_length(void) 874{ 875 struct ccdc_config_params_raw *config_params = 876 &ccdc_cfg.bayer.config_params; 877 unsigned int len; 878 879 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { 880 if ((config_params->alaw.enable) || 881 (config_params->data_sz == CCDC_DATA_8BITS)) 882 len = ccdc_cfg.bayer.win.width; 883 else 884 len = ccdc_cfg.bayer.win.width * 2; 885 } else 886 len = ccdc_cfg.ycbcr.win.width * 2; 887 return ALIGN(len, 32); 888} 889 890static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) 891{ 892 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 893 ccdc_cfg.bayer.frm_fmt = frm_fmt; 894 else 895 ccdc_cfg.ycbcr.frm_fmt = frm_fmt; 896 return 0; 897} 898 899static enum ccdc_frmfmt ccdc_get_frame_format(void) 900{ 901 if (ccdc_cfg.if_type == VPFE_RAW_BAYER) 902 return ccdc_cfg.bayer.frm_fmt; 903 else 904 return ccdc_cfg.ycbcr.frm_fmt; 905} 906 907static int ccdc_getfid(void) 908{ 909 return (regr(MODESET) >> 15) & 1; 910} 911 912/* misc operations */ 913static inline void ccdc_setfbaddr(unsigned long addr) 914{ 915 regw((addr >> 21) & 0x007f, STADRH); 916 regw((addr >> 5) & 0x0ffff, STADRL); 917} 918 919static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) 920{ 921 ccdc_cfg.if_type = params->if_type; 922 923 switch (params->if_type) { 924 case VPFE_BT656: 925 case VPFE_YCBCR_SYNC_16: 926 case VPFE_YCBCR_SYNC_8: 927 ccdc_cfg.ycbcr.vd_pol = params->vdpol; 928 ccdc_cfg.ycbcr.hd_pol = params->hdpol; 929 break; 930 default: 931 /* TODO add support for raw bayer here */ 932 return -EINVAL; 933 } 934 return 0; 935} 936 937static struct ccdc_hw_device ccdc_hw_dev = { 938 .name = "DM355 CCDC", 939 .owner = THIS_MODULE, 940 .hw_ops = { 941 .open = ccdc_open, 942 .close = ccdc_close, 943 .enable = ccdc_enable, 944 .enable_out_to_sdram = ccdc_enable_output_to_sdram, 945 .set_hw_if_params = ccdc_set_hw_if_params, 946 .set_params = ccdc_set_params, 947 .configure = ccdc_configure, 948 .set_buftype = ccdc_set_buftype, 949 .get_buftype = ccdc_get_buftype, 950 .enum_pix = ccdc_enum_pix, 951 .set_pixel_format = ccdc_set_pixel_format, 952 .get_pixel_format = ccdc_get_pixel_format, 953 .set_frame_format = ccdc_set_frame_format, 954 .get_frame_format = ccdc_get_frame_format, 955 .set_image_window = ccdc_set_image_window, 956 .get_image_window = ccdc_get_image_window, 957 .get_line_length = ccdc_get_line_length, 958 .setfbaddr = ccdc_setfbaddr, 959 .getfid = ccdc_getfid, 960 }, 961}; 962 963static int dm355_ccdc_probe(struct platform_device *pdev) 964{ 965 void (*setup_pinmux)(void); 966 struct resource *res; 967 int status = 0; 968 969 /* 970 * first try to register with vpfe. If not correct platform, then we 971 * don't have to iomap 972 */ 973 status = vpfe_register_ccdc_device(&ccdc_hw_dev); 974 if (status < 0) 975 return status; 976 977 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 978 if (!res) { 979 status = -ENODEV; 980 goto fail_nores; 981 } 982 983 res = request_mem_region(res->start, resource_size(res), res->name); 984 if (!res) { 985 status = -EBUSY; 986 goto fail_nores; 987 } 988 989 ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); 990 if (!ccdc_cfg.base_addr) { 991 status = -ENOMEM; 992 goto fail_nomem; 993 } 994 995 /* Platform data holds setup_pinmux function ptr */ 996 if (NULL == pdev->dev.platform_data) { 997 status = -ENODEV; 998 goto fail_nomap; 999 } 1000 setup_pinmux = pdev->dev.platform_data; 1001 /* 1002 * setup Mux configuration for ccdc which may be different for 1003 * different SoCs using this CCDC 1004 */ 1005 setup_pinmux(); 1006 ccdc_cfg.dev = &pdev->dev; 1007 printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); 1008 return 0; 1009fail_nomap: 1010 iounmap(ccdc_cfg.base_addr); 1011fail_nomem: 1012 release_mem_region(res->start, resource_size(res)); 1013fail_nores: 1014 vpfe_unregister_ccdc_device(&ccdc_hw_dev); 1015 return status; 1016} 1017 1018static int dm355_ccdc_remove(struct platform_device *pdev) 1019{ 1020 struct resource *res; 1021 1022 iounmap(ccdc_cfg.base_addr); 1023 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1024 if (res) 1025 release_mem_region(res->start, resource_size(res)); 1026 vpfe_unregister_ccdc_device(&ccdc_hw_dev); 1027 return 0; 1028} 1029 1030static struct platform_driver dm355_ccdc_driver = { 1031 .driver = { 1032 .name = "dm355_ccdc", 1033 }, 1034 .remove = dm355_ccdc_remove, 1035 .probe = dm355_ccdc_probe, 1036}; 1037 1038module_platform_driver(dm355_ccdc_driver); 1039