linux/drivers/media/platform/davinci/isif.c
<<
>>
Prefs
   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 */
  32static const 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 */
  69static 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 */
 128static const u32 isif_raw_bayer_pix_formats[] = {
 129        V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
 130
 131/* Raw YUV formats */
 132static const u32 isif_raw_yuv_pix_formats[] = {
 133        V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
 134
 135/* register access routines */
 136static inline u32 regr(u32 offset)
 137{
 138        return __raw_readl(isif_cfg.base_addr + offset);
 139}
 140
 141static 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 */
 147static 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
 155static 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
 163static 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
 176static 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
 190static void isif_enable_output_to_sdram(int en)
 191{
 192        reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
 193}
 194
 195static 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
 211static 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
 245static 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
 261static 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 */
 268static 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
 309static 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
 371static 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
 398static 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
 482static 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
 528static 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
 691static 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}
 701static 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
 709static 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
 728static 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
 760static 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
 779static 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
 795static 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
 803static 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
 820static 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}
 828static 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
 835static int isif_getfid(void)
 836{
 837        return (regr(MODESET) >> 15) & 0x1;
 838}
 839
 840/* misc operations */
 841static void isif_setfbaddr(unsigned long addr)
 842{
 843        regw((addr >> 21) & 0x07ff, CADU);
 844        regw((addr >> 5) & 0x0ffff, CADL);
 845}
 846
 847static 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. */
 875static 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
 969static 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
 976static 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
 983static 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
1008static 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(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;
1074fail_base_iomap:
1075        release_mem_region(res->start, resource_size(res));
1076        i--;
1077fail_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
1093static 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
1111static struct platform_driver isif_driver = {
1112        .driver = {
1113                .name   = "isif",
1114        },
1115        .remove = isif_remove,
1116        .probe = isif_probe,
1117};
1118
1119module_platform_driver(isif_driver);
1120
1121MODULE_LICENSE("GPL");
1122