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