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