root/drivers/media/platform/davinci/isif.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. regr
  2. regw
  3. reg_modify
  4. regw_lin_tbl
  5. isif_disable_all_modules
  6. isif_enable
  7. isif_enable_output_to_sdram
  8. isif_config_culling
  9. isif_config_gain_offset
  10. isif_restore_defaults
  11. isif_open
  12. isif_setwin
  13. isif_config_bclamp
  14. isif_config_linearization
  15. isif_config_dfc
  16. isif_config_csc
  17. isif_config_raw
  18. isif_set_buftype
  19. isif_get_buftype
  20. isif_enum_pix
  21. isif_set_pixel_format
  22. isif_get_pixel_format
  23. isif_set_image_window
  24. isif_get_image_window
  25. isif_get_line_length
  26. isif_set_frame_format
  27. isif_get_frame_format
  28. isif_getfid
  29. isif_setfbaddr
  30. isif_set_hw_if_params
  31. isif_config_ycbcr
  32. isif_configure
  33. isif_close
  34. isif_probe
  35. isif_remove

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

/* [<][>][^][v][top][bottom][index][help] */