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