1/* 2 * Copyright (C) 2008-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 * Image Sensor Interface (ISIF) driver 19 * 20 * This driver is for configuring the ISIF IP available on DM365 or any other 21 * TI SoCs. This is used for capturing yuv or bayer video or image data 22 * from a decoder or sensor. This IP is similar to the CCDC IP on DM355 23 * and DM6446, but with enhanced or additional ip blocks. The driver 24 * configures the ISIF upon commands from the vpfe bridge driver through 25 * ccdc_hw_device interface. 26 * 27 * TODO: 1) Raw bayer parameter settings and bayer capture 28 * 2) Add support for control ioctl 29 */ 30#include <linux/delay.h> 31#include <linux/platform_device.h> 32#include <linux/uaccess.h> 33#include <linux/io.h> 34#include <linux/videodev2.h> 35#include <linux/err.h> 36#include <linux/module.h> 37 38#include <mach/mux.h> 39 40#include <media/davinci/isif.h> 41#include <media/davinci/vpss.h> 42 43#include "isif_regs.h" 44#include "ccdc_hw_device.h" 45 46/* Defaults for module configuration parameters */ 47static struct isif_config_params_raw isif_config_defaults = { 48 .linearize = { 49 .en = 0, 50 .corr_shft = ISIF_NO_SHIFT, 51 .scale_fact = {1, 0}, 52 }, 53 .df_csc = { 54 .df_or_csc = 0, 55 .csc = { 56 .en = 0, 57 }, 58 }, 59 .dfc = { 60 .en = 0, 61 }, 62 .bclamp = { 63 .en = 0, 64 }, 65 .gain_offset = { 66 .gain = { 67 .r_ye = {1, 0}, 68 .gr_cy = {1, 0}, 69 .gb_g = {1, 0}, 70 .b_mg = {1, 0}, 71 }, 72 }, 73 .culling = { 74 .hcpat_odd = 0xff, 75 .hcpat_even = 0xff, 76 .vcpat = 0xff, 77 }, 78 .compress = { 79 .alg = ISIF_ALAW, 80 }, 81}; 82 83/* ISIF operation configuration */ 84static struct isif_oper_config { 85 struct device *dev; 86 enum vpfe_hw_if_type if_type; 87 struct isif_ycbcr_config ycbcr; 88 struct isif_params_raw bayer; 89 enum isif_data_pack data_pack; 90 /* ISIF base address */ 91 void __iomem *base_addr; 92 /* ISIF Linear Table 0 */ 93 void __iomem *linear_tbl0_addr; 94 /* ISIF Linear Table 1 */ 95 void __iomem *linear_tbl1_addr; 96} isif_cfg = { 97 .ycbcr = { 98 .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, 99 .frm_fmt = CCDC_FRMFMT_INTERLACED, 100 .win = ISIF_WIN_NTSC, 101 .fid_pol = VPFE_PINPOL_POSITIVE, 102 .vd_pol = VPFE_PINPOL_POSITIVE, 103 .hd_pol = VPFE_PINPOL_POSITIVE, 104 .pix_order = CCDC_PIXORDER_CBYCRY, 105 .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, 106 }, 107 .bayer = { 108 .pix_fmt = CCDC_PIXFMT_RAW, 109 .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, 110 .win = ISIF_WIN_VGA, 111 .fid_pol = VPFE_PINPOL_POSITIVE, 112 .vd_pol = VPFE_PINPOL_POSITIVE, 113 .hd_pol = VPFE_PINPOL_POSITIVE, 114 .gain = { 115 .r_ye = {1, 0}, 116 .gr_cy = {1, 0}, 117 .gb_g = {1, 0}, 118 .b_mg = {1, 0}, 119 }, 120 .cfa_pat = ISIF_CFA_PAT_MOSAIC, 121 .data_msb = ISIF_BIT_MSB_11, 122 .config_params = { 123 .data_shift = ISIF_NO_SHIFT, 124 .col_pat_field0 = { 125 .olop = ISIF_GREEN_BLUE, 126 .olep = ISIF_BLUE, 127 .elop = ISIF_RED, 128 .elep = ISIF_GREEN_RED, 129 }, 130 .col_pat_field1 = { 131 .olop = ISIF_GREEN_BLUE, 132 .olep = ISIF_BLUE, 133 .elop = ISIF_RED, 134 .elep = ISIF_GREEN_RED, 135 }, 136 .test_pat_gen = 0, 137 }, 138 }, 139 .data_pack = ISIF_DATA_PACK8, 140}; 141 142/* Raw Bayer formats */ 143static const u32 isif_raw_bayer_pix_formats[] = { 144 V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; 145 146/* Raw YUV formats */ 147static const u32 isif_raw_yuv_pix_formats[] = { 148 V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; 149 150/* register access routines */ 151static inline u32 regr(u32 offset) 152{ 153 return __raw_readl(isif_cfg.base_addr + offset); 154} 155 156static inline void regw(u32 val, u32 offset) 157{ 158 __raw_writel(val, isif_cfg.base_addr + offset); 159} 160 161/* reg_modify() - read, modify and write register */ 162static inline u32 reg_modify(u32 mask, u32 val, u32 offset) 163{ 164 u32 new_val = (regr(offset) & ~mask) | (val & mask); 165 166 regw(new_val, offset); 167 return new_val; 168} 169 170static inline void regw_lin_tbl(u32 val, u32 offset, int i) 171{ 172 if (!i) 173 __raw_writel(val, isif_cfg.linear_tbl0_addr + offset); 174 else 175 __raw_writel(val, isif_cfg.linear_tbl1_addr + offset); 176} 177 178static void isif_disable_all_modules(void) 179{ 180 /* disable BC */ 181 regw(0, CLAMPCFG); 182 /* disable vdfc */ 183 regw(0, DFCCTL); 184 /* disable CSC */ 185 regw(0, CSCCTL); 186 /* disable linearization */ 187 regw(0, LINCFG0); 188 /* disable other modules here as they are supported */ 189} 190 191static void isif_enable(int en) 192{ 193 if (!en) { 194 /* Before disable isif, disable all ISIF modules */ 195 isif_disable_all_modules(); 196 /* 197 * wait for next VD. Assume lowest scan rate is 12 Hz. So 198 * 100 msec delay is good enough 199 */ 200 msleep(100); 201 } 202 reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN); 203} 204 205static void isif_enable_output_to_sdram(int en) 206{ 207 reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); 208} 209 210static void isif_config_culling(struct isif_cul *cul) 211{ 212 u32 val; 213 214 /* Horizontal pattern */ 215 val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd; 216 regw(val, CULH); 217 218 /* vertical pattern */ 219 regw(cul->vcpat, CULV); 220 221 /* LPF */ 222 reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT, 223 cul->en_lpf << ISIF_LPF_SHIFT, MODESET); 224} 225 226static void isif_config_gain_offset(void) 227{ 228 struct isif_gain_offsets_adj *gain_off_p = 229 &isif_cfg.bayer.config_params.gain_offset; 230 u32 val; 231 232 val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) | 233 (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) | 234 (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) | 235 (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) | 236 (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) | 237 (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT); 238 239 reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); 240 241 val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) | 242 gain_off_p->gain.r_ye.decimal; 243 regw(val, CRGAIN); 244 245 val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) | 246 gain_off_p->gain.gr_cy.decimal; 247 regw(val, CGRGAIN); 248 249 val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) | 250 gain_off_p->gain.gb_g.decimal; 251 regw(val, CGBGAIN); 252 253 val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) | 254 gain_off_p->gain.b_mg.decimal; 255 regw(val, CBGAIN); 256 257 regw(gain_off_p->offset, COFSTA); 258} 259 260static void isif_restore_defaults(void) 261{ 262 enum vpss_ccdc_source_sel source = VPSS_CCDCIN; 263 264 dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults..."); 265 isif_cfg.bayer.config_params = isif_config_defaults; 266 /* Enable clock to ISIF, IPIPEIF and BL */ 267 vpss_enable_clock(VPSS_CCDC_CLOCK, 1); 268 vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); 269 vpss_enable_clock(VPSS_BL_CLOCK, 1); 270 /* Set default offset and gain */ 271 isif_config_gain_offset(); 272 vpss_select_ccdc_source(source); 273 dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults..."); 274} 275 276static int isif_open(struct device *device) 277{ 278 isif_restore_defaults(); 279 return 0; 280} 281 282/* This function will configure the window size to be capture in ISIF reg */ 283static void isif_setwin(struct v4l2_rect *image_win, 284 enum ccdc_frmfmt frm_fmt, int ppc) 285{ 286 int horz_start, horz_nr_pixels; 287 int vert_start, vert_nr_lines; 288 int mid_img = 0; 289 290 dev_dbg(isif_cfg.dev, "\nStarting isif_setwin..."); 291 /* 292 * ppc - per pixel count. indicates how many pixels per cell 293 * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. 294 * raw capture this is 1 295 */ 296 horz_start = image_win->left << (ppc - 1); 297 horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; 298 299 /* Writing the horizontal info into the registers */ 300 regw(horz_start & START_PX_HOR_MASK, SPH); 301 regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH); 302 vert_start = image_win->top; 303 304 if (frm_fmt == CCDC_FRMFMT_INTERLACED) { 305 vert_nr_lines = (image_win->height >> 1) - 1; 306 vert_start >>= 1; 307 /* To account for VD since line 0 doesn't have any data */ 308 vert_start += 1; 309 } else { 310 /* To account for VD since line 0 doesn't have any data */ 311 vert_start += 1; 312 vert_nr_lines = image_win->height - 1; 313 /* configure VDINT0 and VDINT1 */ 314 mid_img = vert_start + (image_win->height / 2); 315 regw(mid_img, VDINT1); 316 } 317 318 regw(0, VDINT0); 319 regw(vert_start & START_VER_ONE_MASK, SLV0); 320 regw(vert_start & START_VER_TWO_MASK, SLV1); 321 regw(vert_nr_lines & NUM_LINES_VER, LNV); 322} 323 324static void isif_config_bclamp(struct isif_black_clamp *bc) 325{ 326 u32 val; 327 328 /* 329 * DC Offset is always added to image data irrespective of bc enable 330 * status 331 */ 332 regw(bc->dc_offset, CLDCOFST); 333 334 if (bc->en) { 335 val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT; 336 337 /* Enable BC and horizontal clamp caculation paramaters */ 338 val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT); 339 340 regw(val, CLAMPCFG); 341 342 if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) { 343 /* 344 * Window count for calculation 345 * Base window selection 346 * pixel limit 347 * Horizontal size of window 348 * vertical size of the window 349 * Horizontal start position of the window 350 * Vertical start position of the window 351 */ 352 val = bc->horz.win_count_calc | 353 ((!!bc->horz.base_win_sel_calc) << 354 ISIF_HORZ_BC_WIN_SEL_SHIFT) | 355 ((!!bc->horz.clamp_pix_limit) << 356 ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | 357 (bc->horz.win_h_sz_calc << 358 ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | 359 (bc->horz.win_v_sz_calc << 360 ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); 361 regw(val, CLHWIN0); 362 363 regw(bc->horz.win_start_h_calc, CLHWIN1); 364 regw(bc->horz.win_start_v_calc, CLHWIN2); 365 } 366 367 /* vertical clamp caculation paramaters */ 368 369 /* Reset clamp value sel for previous line */ 370 val |= 371 (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) | 372 (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT); 373 regw(val, CLVWIN0); 374 375 /* Optical Black horizontal start position */ 376 regw(bc->vert.ob_start_h, CLVWIN1); 377 /* Optical Black vertical start position */ 378 regw(bc->vert.ob_start_v, CLVWIN2); 379 /* Optical Black vertical size for calculation */ 380 regw(bc->vert.ob_v_sz_calc, CLVWIN3); 381 /* Vertical start position for BC subtraction */ 382 regw(bc->vert_start_sub, CLSV); 383 } 384} 385 386static void isif_config_linearization(struct isif_linearize *linearize) 387{ 388 u32 val, i; 389 390 if (!linearize->en) { 391 regw(0, LINCFG0); 392 return; 393 } 394 395 /* shift value for correction & enable linearization (set lsb) */ 396 val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1; 397 regw(val, LINCFG0); 398 399 /* Scale factor */ 400 val = ((!!linearize->scale_fact.integer) << 401 ISIF_LIN_SCALE_FACT_INTEG_SHIFT) | 402 linearize->scale_fact.decimal; 403 regw(val, LINCFG1); 404 405 for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) { 406 if (i % 2) 407 regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1); 408 else 409 regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0); 410 } 411} 412 413static int isif_config_dfc(struct isif_dfc *vdfc) 414{ 415 /* initialize retries to loop for max ~ 250 usec */ 416 u32 val, count, retries = loops_per_jiffy / (4000/HZ); 417 int i; 418 419 if (!vdfc->en) 420 return 0; 421 422 /* Correction mode */ 423 val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT); 424 425 /* Correct whole line or partial */ 426 if (vdfc->corr_whole_line) 427 val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; 428 429 /* level shift value */ 430 val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT; 431 432 regw(val, DFCCTL); 433 434 /* Defect saturation level */ 435 regw(vdfc->def_sat_level, VDFSATLV); 436 437 regw(vdfc->table[0].pos_vert, DFCMEM0); 438 regw(vdfc->table[0].pos_horz, DFCMEM1); 439 if (vdfc->corr_mode == ISIF_VDFC_NORMAL || 440 vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { 441 regw(vdfc->table[0].level_at_pos, DFCMEM2); 442 regw(vdfc->table[0].level_up_pixels, DFCMEM3); 443 regw(vdfc->table[0].level_low_pixels, DFCMEM4); 444 } 445 446 /* set DFCMARST and set DFCMWR */ 447 val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1; 448 regw(val, DFCMEMCTL); 449 450 count = retries; 451 while (count && (regr(DFCMEMCTL) & 0x1)) 452 count--; 453 454 if (!count) { 455 dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n"); 456 return -1; 457 } 458 459 for (i = 1; i < vdfc->num_vdefects; i++) { 460 regw(vdfc->table[i].pos_vert, DFCMEM0); 461 regw(vdfc->table[i].pos_horz, DFCMEM1); 462 if (vdfc->corr_mode == ISIF_VDFC_NORMAL || 463 vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { 464 regw(vdfc->table[i].level_at_pos, DFCMEM2); 465 regw(vdfc->table[i].level_up_pixels, DFCMEM3); 466 regw(vdfc->table[i].level_low_pixels, DFCMEM4); 467 } 468 val = regr(DFCMEMCTL); 469 /* clear DFCMARST and set DFCMWR */ 470 val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); 471 val |= 1; 472 regw(val, DFCMEMCTL); 473 474 count = retries; 475 while (count && (regr(DFCMEMCTL) & 0x1)) 476 count--; 477 478 if (!count) { 479 dev_err(isif_cfg.dev, 480 "defect table write timeout !!!\n"); 481 return -1; 482 } 483 } 484 if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) { 485 /* Extra cycle needed */ 486 regw(0, DFCMEM0); 487 regw(0x1FFF, DFCMEM1); 488 regw(1, DFCMEMCTL); 489 } 490 491 /* enable VDFC */ 492 reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT), 493 DFCCTL); 494 return 0; 495} 496 497static void isif_config_csc(struct isif_df_csc *df_csc) 498{ 499 u32 val1 = 0, val2 = 0, i; 500 501 if (!df_csc->csc.en) { 502 regw(0, CSCCTL); 503 return; 504 } 505 for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) { 506 if ((i % 2) == 0) { 507 /* CSCM - LSB */ 508 val1 = (df_csc->csc.coeff[i].integer << 509 ISIF_CSC_COEF_INTEG_SHIFT) | 510 df_csc->csc.coeff[i].decimal; 511 } else { 512 513 /* CSCM - MSB */ 514 val2 = (df_csc->csc.coeff[i].integer << 515 ISIF_CSC_COEF_INTEG_SHIFT) | 516 df_csc->csc.coeff[i].decimal; 517 val2 <<= ISIF_CSCM_MSB_SHIFT; 518 val2 |= val1; 519 regw(val2, (CSCM0 + ((i - 1) << 1))); 520 } 521 } 522 523 /* program the active area */ 524 regw(df_csc->start_pix, FMTSPH); 525 /* 526 * one extra pixel as required for CSC. Actually number of 527 * pixel - 1 should be configured in this register. So we 528 * need to subtract 1 before writing to FMTSPH, but we will 529 * not do this since csc requires one extra pixel 530 */ 531 regw(df_csc->num_pixels, FMTLNH); 532 regw(df_csc->start_line, FMTSLV); 533 /* 534 * one extra line as required for CSC. See reason documented for 535 * num_pixels 536 */ 537 regw(df_csc->num_lines, FMTLNV); 538 539 /* Enable CSC */ 540 regw(1, CSCCTL); 541} 542 543static int isif_config_raw(void) 544{ 545 struct isif_params_raw *params = &isif_cfg.bayer; 546 struct isif_config_params_raw *module_params = 547 &isif_cfg.bayer.config_params; 548 struct vpss_pg_frame_size frame_size; 549 struct vpss_sync_pol sync; 550 u32 val; 551 552 dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n"); 553 554 /* 555 * Configure CCDCFG register:- 556 * Set CCD Not to swap input since input is RAW data 557 * Set FID detection function to Latch at V-Sync 558 * Set WENLOG - isif valid area 559 * Set TRGSEL 560 * Set EXTRG 561 * Packed to 8 or 16 bits 562 */ 563 564 val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | 565 ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | 566 ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack; 567 568 dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val); 569 regw(val, CCDCFG); 570 571 /* 572 * Configure the vertical sync polarity(MODESET.VDPOL) 573 * Configure the horizontal sync polarity (MODESET.HDPOL) 574 * Configure frame id polarity (MODESET.FLDPOL) 575 * Configure data polarity 576 * Configure External WEN Selection 577 * Configure frame format(progressive or interlace) 578 * Configure pixel format (Input mode) 579 * Configure the data shift 580 */ 581 582 val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) | 583 (params->hd_pol << ISIF_HD_POL_SHIFT) | 584 (params->fid_pol << ISIF_FID_POL_SHIFT) | 585 (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) | 586 (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) | 587 (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | 588 (params->pix_fmt << ISIF_INPUT_SHIFT) | 589 (params->config_params.data_shift << ISIF_DATASFT_SHIFT); 590 591 regw(val, MODESET); 592 dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val); 593 594 /* 595 * Configure GAMMAWD register 596 * CFA pattern setting 597 */ 598 val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT; 599 600 /* Gamma msb */ 601 if (module_params->compress.alg == ISIF_ALAW) 602 val |= ISIF_ALAW_ENABLE; 603 604 val |= (params->data_msb << ISIF_ALAW_GAMMA_WD_SHIFT); 605 regw(val, CGAMMAWD); 606 607 /* Configure DPCM compression settings */ 608 if (module_params->compress.alg == ISIF_DPCM) { 609 val = BIT(ISIF_DPCM_EN_SHIFT) | 610 (module_params->compress.pred << 611 ISIF_DPCM_PREDICTOR_SHIFT); 612 } 613 614 regw(val, MISC); 615 616 /* Configure Gain & Offset */ 617 isif_config_gain_offset(); 618 619 /* Configure Color pattern */ 620 val = (params->config_params.col_pat_field0.olop) | 621 (params->config_params.col_pat_field0.olep << 2) | 622 (params->config_params.col_pat_field0.elop << 4) | 623 (params->config_params.col_pat_field0.elep << 6) | 624 (params->config_params.col_pat_field1.olop << 8) | 625 (params->config_params.col_pat_field1.olep << 10) | 626 (params->config_params.col_pat_field1.elop << 12) | 627 (params->config_params.col_pat_field1.elep << 14); 628 regw(val, CCOLP); 629 dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val); 630 631 /* Configure HSIZE register */ 632 val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT; 633 634 /* calculate line offset in 32 bytes based on pack value */ 635 if (isif_cfg.data_pack == ISIF_PACK_8BIT) 636 val |= ((params->win.width + 31) >> 5); 637 else if (isif_cfg.data_pack == ISIF_PACK_12BIT) 638 val |= (((params->win.width + 639 (params->win.width >> 2)) + 31) >> 5); 640 else 641 val |= (((params->win.width * 2) + 31) >> 5); 642 regw(val, HSIZE); 643 644 /* Configure SDOFST register */ 645 if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { 646 if (params->image_invert_en) { 647 /* For interlace inverse mode */ 648 regw(0x4B6D, SDOFST); 649 dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n"); 650 } else { 651 /* For interlace non inverse mode */ 652 regw(0x0B6D, SDOFST); 653 dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n"); 654 } 655 } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { 656 if (params->image_invert_en) { 657 /* For progressive inverse mode */ 658 regw(0x4000, SDOFST); 659 dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n"); 660 } else { 661 /* For progressive non inverse mode */ 662 regw(0x0000, SDOFST); 663 dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n"); 664 } 665 } 666 667 /* Configure video window */ 668 isif_setwin(¶ms->win, params->frm_fmt, 1); 669 670 /* Configure Black Clamp */ 671 isif_config_bclamp(&module_params->bclamp); 672 673 /* Configure Vertical Defection Pixel Correction */ 674 if (isif_config_dfc(&module_params->dfc) < 0) 675 return -EFAULT; 676 677 if (!module_params->df_csc.df_or_csc) 678 /* Configure Color Space Conversion */ 679 isif_config_csc(&module_params->df_csc); 680 681 isif_config_linearization(&module_params->linearize); 682 683 /* Configure Culling */ 684 isif_config_culling(&module_params->culling); 685 686 /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */ 687 regw(module_params->horz_offset, DATAHOFST); 688 regw(module_params->vert_offset, DATAVOFST); 689 690 /* Setup test pattern if enabled */ 691 if (params->config_params.test_pat_gen) { 692 /* Use the HD/VD pol settings from user */ 693 sync.ccdpg_hdpol = params->hd_pol; 694 sync.ccdpg_vdpol = params->vd_pol; 695 dm365_vpss_set_sync_pol(sync); 696 frame_size.hlpfr = isif_cfg.bayer.win.width; 697 frame_size.pplen = isif_cfg.bayer.win.height; 698 dm365_vpss_set_pg_frame_size(frame_size); 699 vpss_select_ccdc_source(VPSS_PGLPBK); 700 } 701 702 dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n"); 703 return 0; 704} 705 706static int isif_set_buftype(enum ccdc_buftype buf_type) 707{ 708 if (isif_cfg.if_type == VPFE_RAW_BAYER) 709 isif_cfg.bayer.buf_type = buf_type; 710 else 711 isif_cfg.ycbcr.buf_type = buf_type; 712 713 return 0; 714 715} 716static enum ccdc_buftype isif_get_buftype(void) 717{ 718 if (isif_cfg.if_type == VPFE_RAW_BAYER) 719 return isif_cfg.bayer.buf_type; 720 721 return isif_cfg.ycbcr.buf_type; 722} 723 724static int isif_enum_pix(u32 *pix, int i) 725{ 726 int ret = -EINVAL; 727 728 if (isif_cfg.if_type == VPFE_RAW_BAYER) { 729 if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) { 730 *pix = isif_raw_bayer_pix_formats[i]; 731 ret = 0; 732 } 733 } else { 734 if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) { 735 *pix = isif_raw_yuv_pix_formats[i]; 736 ret = 0; 737 } 738 } 739 740 return ret; 741} 742 743static int isif_set_pixel_format(unsigned int pixfmt) 744{ 745 if (isif_cfg.if_type == VPFE_RAW_BAYER) { 746 if (pixfmt == V4L2_PIX_FMT_SBGGR8) { 747 if ((isif_cfg.bayer.config_params.compress.alg != 748 ISIF_ALAW) && 749 (isif_cfg.bayer.config_params.compress.alg != 750 ISIF_DPCM)) { 751 dev_dbg(isif_cfg.dev, 752 "Either configure A-Law or DPCM\n"); 753 return -EINVAL; 754 } 755 isif_cfg.data_pack = ISIF_PACK_8BIT; 756 } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) { 757 isif_cfg.bayer.config_params.compress.alg = 758 ISIF_NO_COMPRESSION; 759 isif_cfg.data_pack = ISIF_PACK_16BIT; 760 } else 761 return -EINVAL; 762 isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; 763 } else { 764 if (pixfmt == V4L2_PIX_FMT_YUYV) 765 isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; 766 else if (pixfmt == V4L2_PIX_FMT_UYVY) 767 isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; 768 else 769 return -EINVAL; 770 isif_cfg.data_pack = ISIF_PACK_8BIT; 771 } 772 return 0; 773} 774 775static u32 isif_get_pixel_format(void) 776{ 777 u32 pixfmt; 778 779 if (isif_cfg.if_type == VPFE_RAW_BAYER) 780 if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW || 781 isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM) 782 pixfmt = V4L2_PIX_FMT_SBGGR8; 783 else 784 pixfmt = V4L2_PIX_FMT_SBGGR16; 785 else { 786 if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) 787 pixfmt = V4L2_PIX_FMT_YUYV; 788 else 789 pixfmt = V4L2_PIX_FMT_UYVY; 790 } 791 return pixfmt; 792} 793 794static int isif_set_image_window(struct v4l2_rect *win) 795{ 796 if (isif_cfg.if_type == VPFE_RAW_BAYER) { 797 isif_cfg.bayer.win.top = win->top; 798 isif_cfg.bayer.win.left = win->left; 799 isif_cfg.bayer.win.width = win->width; 800 isif_cfg.bayer.win.height = win->height; 801 } else { 802 isif_cfg.ycbcr.win.top = win->top; 803 isif_cfg.ycbcr.win.left = win->left; 804 isif_cfg.ycbcr.win.width = win->width; 805 isif_cfg.ycbcr.win.height = win->height; 806 } 807 return 0; 808} 809 810static void isif_get_image_window(struct v4l2_rect *win) 811{ 812 if (isif_cfg.if_type == VPFE_RAW_BAYER) 813 *win = isif_cfg.bayer.win; 814 else 815 *win = isif_cfg.ycbcr.win; 816} 817 818static unsigned int isif_get_line_length(void) 819{ 820 unsigned int len; 821 822 if (isif_cfg.if_type == VPFE_RAW_BAYER) { 823 if (isif_cfg.data_pack == ISIF_PACK_8BIT) 824 len = ((isif_cfg.bayer.win.width)); 825 else if (isif_cfg.data_pack == ISIF_PACK_12BIT) 826 len = (((isif_cfg.bayer.win.width * 2) + 827 (isif_cfg.bayer.win.width >> 2))); 828 else 829 len = (((isif_cfg.bayer.win.width * 2))); 830 } else 831 len = (((isif_cfg.ycbcr.win.width * 2))); 832 return ALIGN(len, 32); 833} 834 835static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt) 836{ 837 if (isif_cfg.if_type == VPFE_RAW_BAYER) 838 isif_cfg.bayer.frm_fmt = frm_fmt; 839 else 840 isif_cfg.ycbcr.frm_fmt = frm_fmt; 841 return 0; 842} 843static enum ccdc_frmfmt isif_get_frame_format(void) 844{ 845 if (isif_cfg.if_type == VPFE_RAW_BAYER) 846 return isif_cfg.bayer.frm_fmt; 847 return isif_cfg.ycbcr.frm_fmt; 848} 849 850static int isif_getfid(void) 851{ 852 return (regr(MODESET) >> 15) & 0x1; 853} 854 855/* misc operations */ 856static void isif_setfbaddr(unsigned long addr) 857{ 858 regw((addr >> 21) & 0x07ff, CADU); 859 regw((addr >> 5) & 0x0ffff, CADL); 860} 861 862static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) 863{ 864 isif_cfg.if_type = params->if_type; 865 866 switch (params->if_type) { 867 case VPFE_BT656: 868 case VPFE_BT656_10BIT: 869 case VPFE_YCBCR_SYNC_8: 870 isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; 871 isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; 872 break; 873 case VPFE_BT1120: 874 case VPFE_YCBCR_SYNC_16: 875 isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT; 876 isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; 877 break; 878 case VPFE_RAW_BAYER: 879 isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; 880 break; 881 default: 882 dev_dbg(isif_cfg.dev, "Invalid interface type\n"); 883 return -EINVAL; 884 } 885 886 return 0; 887} 888 889/* This function will configure ISIF for YCbCr parameters. */ 890static int isif_config_ycbcr(void) 891{ 892 struct isif_ycbcr_config *params = &isif_cfg.ycbcr; 893 struct vpss_pg_frame_size frame_size; 894 u32 modeset = 0, ccdcfg = 0; 895 struct vpss_sync_pol sync; 896 897 dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); 898 899 /* configure pixel format or input mode */ 900 modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) | 901 (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | 902 (params->fid_pol << ISIF_FID_POL_SHIFT) | 903 (params->hd_pol << ISIF_HD_POL_SHIFT) | 904 (params->vd_pol << ISIF_VD_POL_SHIFT); 905 906 /* pack the data to 8-bit ISIFCFG */ 907 switch (isif_cfg.if_type) { 908 case VPFE_BT656: 909 if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { 910 dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); 911 return -EINVAL; 912 } 913 modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT); 914 regw(3, REC656IF); 915 ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR; 916 break; 917 case VPFE_BT656_10BIT: 918 if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { 919 dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); 920 return -EINVAL; 921 } 922 /* setup BT.656, embedded sync */ 923 regw(3, REC656IF); 924 /* enable 10 bit mode in ccdcfg */ 925 ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR | 926 ISIF_BW656_ENABLE; 927 break; 928 case VPFE_BT1120: 929 if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { 930 dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); 931 return -EINVAL; 932 } 933 regw(3, REC656IF); 934 break; 935 936 case VPFE_YCBCR_SYNC_8: 937 ccdcfg |= ISIF_DATA_PACK8; 938 ccdcfg |= ISIF_YCINSWP_YCBCR; 939 if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { 940 dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); 941 return -EINVAL; 942 } 943 break; 944 case VPFE_YCBCR_SYNC_16: 945 if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { 946 dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); 947 return -EINVAL; 948 } 949 break; 950 default: 951 /* should never come here */ 952 dev_dbg(isif_cfg.dev, "Invalid interface type\n"); 953 return -EINVAL; 954 } 955 956 regw(modeset, MODESET); 957 958 /* Set up pix order */ 959 ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT; 960 961 regw(ccdcfg, CCDCFG); 962 963 /* configure video window */ 964 if ((isif_cfg.if_type == VPFE_BT1120) || 965 (isif_cfg.if_type == VPFE_YCBCR_SYNC_16)) 966 isif_setwin(¶ms->win, params->frm_fmt, 1); 967 else 968 isif_setwin(¶ms->win, params->frm_fmt, 2); 969 970 /* 971 * configure the horizontal line offset 972 * this is done by rounding up width to a multiple of 16 pixels 973 * and multiply by two to account for y:cb:cr 4:2:2 data 974 */ 975 regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE); 976 977 /* configure the memory line offset */ 978 if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) && 979 (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)) 980 /* two fields are interleaved in memory */ 981 regw(0x00000249, SDOFST); 982 983 /* Setup test pattern if enabled */ 984 if (isif_cfg.bayer.config_params.test_pat_gen) { 985 sync.ccdpg_hdpol = params->hd_pol; 986 sync.ccdpg_vdpol = params->vd_pol; 987 dm365_vpss_set_sync_pol(sync); 988 dm365_vpss_set_pg_frame_size(frame_size); 989 } 990 return 0; 991} 992 993static int isif_configure(void) 994{ 995 if (isif_cfg.if_type == VPFE_RAW_BAYER) 996 return isif_config_raw(); 997 return isif_config_ycbcr(); 998} 999 1000static int isif_close(struct device *device) 1001{ 1002 /* copy defaults to module params */ 1003 isif_cfg.bayer.config_params = isif_config_defaults; 1004 return 0; 1005} 1006 1007static struct ccdc_hw_device isif_hw_dev = { 1008 .name = "ISIF", 1009 .owner = THIS_MODULE, 1010 .hw_ops = { 1011 .open = isif_open, 1012 .close = isif_close, 1013 .enable = isif_enable, 1014 .enable_out_to_sdram = isif_enable_output_to_sdram, 1015 .set_hw_if_params = isif_set_hw_if_params, 1016 .configure = isif_configure, 1017 .set_buftype = isif_set_buftype, 1018 .get_buftype = isif_get_buftype, 1019 .enum_pix = isif_enum_pix, 1020 .set_pixel_format = isif_set_pixel_format, 1021 .get_pixel_format = isif_get_pixel_format, 1022 .set_frame_format = isif_set_frame_format, 1023 .get_frame_format = isif_get_frame_format, 1024 .set_image_window = isif_set_image_window, 1025 .get_image_window = isif_get_image_window, 1026 .get_line_length = isif_get_line_length, 1027 .setfbaddr = isif_setfbaddr, 1028 .getfid = isif_getfid, 1029 }, 1030}; 1031 1032static int isif_probe(struct platform_device *pdev) 1033{ 1034 void (*setup_pinmux)(void); 1035 struct resource *res; 1036 void *__iomem addr; 1037 int status = 0, i; 1038 1039 /* Platform data holds setup_pinmux function ptr */ 1040 if (!pdev->dev.platform_data) 1041 return -ENODEV; 1042 1043 /* 1044 * first try to register with vpfe. If not correct platform, then we 1045 * don't have to iomap 1046 */ 1047 status = vpfe_register_ccdc_device(&isif_hw_dev); 1048 if (status < 0) 1049 return status; 1050 1051 setup_pinmux = pdev->dev.platform_data; 1052 /* 1053 * setup Mux configuration for ccdc which may be different for 1054 * different SoCs using this CCDC 1055 */ 1056 setup_pinmux(); 1057 1058 i = 0; 1059 /* Get the ISIF base address, linearization table0 and table1 addr. */ 1060 while (i < 3) { 1061 res = platform_get_resource(pdev, IORESOURCE_MEM, i); 1062 if (!res) { 1063 status = -ENODEV; 1064 goto fail_nobase_res; 1065 } 1066 res = request_mem_region(res->start, resource_size(res), 1067 res->name); 1068 if (!res) { 1069 status = -EBUSY; 1070 goto fail_nobase_res; 1071 } 1072 addr = ioremap_nocache(res->start, resource_size(res)); 1073 if (!addr) { 1074 status = -ENOMEM; 1075 goto fail_base_iomap; 1076 } 1077 switch (i) { 1078 case 0: 1079 /* ISIF base address */ 1080 isif_cfg.base_addr = addr; 1081 break; 1082 case 1: 1083 /* ISIF linear tbl0 address */ 1084 isif_cfg.linear_tbl0_addr = addr; 1085 break; 1086 default: 1087 /* ISIF linear tbl0 address */ 1088 isif_cfg.linear_tbl1_addr = addr; 1089 break; 1090 } 1091 i++; 1092 } 1093 isif_cfg.dev = &pdev->dev; 1094 1095 printk(KERN_NOTICE "%s is registered with vpfe.\n", 1096 isif_hw_dev.name); 1097 return 0; 1098fail_base_iomap: 1099 release_mem_region(res->start, resource_size(res)); 1100 i--; 1101fail_nobase_res: 1102 if (isif_cfg.base_addr) 1103 iounmap(isif_cfg.base_addr); 1104 if (isif_cfg.linear_tbl0_addr) 1105 iounmap(isif_cfg.linear_tbl0_addr); 1106 1107 while (i >= 0) { 1108 res = platform_get_resource(pdev, IORESOURCE_MEM, i); 1109 release_mem_region(res->start, resource_size(res)); 1110 i--; 1111 } 1112 vpfe_unregister_ccdc_device(&isif_hw_dev); 1113 return status; 1114} 1115 1116static int isif_remove(struct platform_device *pdev) 1117{ 1118 struct resource *res; 1119 int i = 0; 1120 1121 iounmap(isif_cfg.base_addr); 1122 iounmap(isif_cfg.linear_tbl0_addr); 1123 iounmap(isif_cfg.linear_tbl1_addr); 1124 while (i < 3) { 1125 res = platform_get_resource(pdev, IORESOURCE_MEM, i); 1126 if (res) 1127 release_mem_region(res->start, resource_size(res)); 1128 i++; 1129 } 1130 vpfe_unregister_ccdc_device(&isif_hw_dev); 1131 return 0; 1132} 1133 1134static struct platform_driver isif_driver = { 1135 .driver = { 1136 .name = "isif", 1137 }, 1138 .remove = isif_remove, 1139 .probe = isif_probe, 1140}; 1141 1142module_platform_driver(isif_driver); 1143 1144MODULE_LICENSE("GPL"); 1145