linux/drivers/media/video/davinci/dm355_ccdc.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005-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 * CCDC hardware module for DM355
  19 * ------------------------------
  20 *
  21 * This module is for configuring DM355 CCD controller of VPFE to capture
  22 * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
  23 * such as Defect Pixel Correction, Color Space Conversion etc to
  24 * pre-process the Bayer RGB data, before writing it to SDRAM. This
  25 * module also allows application to configure individual
  26 * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
  27 * To do so, application include dm355_ccdc.h and vpfe_capture.h header
  28 * files. The setparams() API is called by vpfe_capture driver
  29 * to configure module parameters
  30 *
  31 * TODO: 1) Raw bayer parameter settings and bayer capture
  32 *       2) Split module parameter structure to module specific ioctl structs
  33 *       3) add support for lense shading correction
  34 *       4) investigate if enum used for user space type definition
  35 *          to be replaced by #defines or integer
  36 */
  37#include <linux/platform_device.h>
  38#include <linux/uaccess.h>
  39#include <linux/videodev2.h>
  40#include <media/davinci/dm355_ccdc.h>
  41#include <media/davinci/vpss.h>
  42#include "dm355_ccdc_regs.h"
  43#include "ccdc_hw_device.h"
  44
  45MODULE_LICENSE("GPL");
  46MODULE_DESCRIPTION("CCDC Driver for DM355");
  47MODULE_AUTHOR("Texas Instruments");
  48
  49static struct device *dev;
  50
  51/* Object for CCDC raw mode */
  52static struct ccdc_params_raw ccdc_hw_params_raw = {
  53        .pix_fmt = CCDC_PIXFMT_RAW,
  54        .frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
  55        .win = CCDC_WIN_VGA,
  56        .fid_pol = VPFE_PINPOL_POSITIVE,
  57        .vd_pol = VPFE_PINPOL_POSITIVE,
  58        .hd_pol = VPFE_PINPOL_POSITIVE,
  59        .gain = {
  60                .r_ye = 256,
  61                .gb_g = 256,
  62                .gr_cy = 256,
  63                .b_mg = 256
  64        },
  65        .config_params = {
  66                .datasft = 2,
  67                .data_sz = CCDC_DATA_10BITS,
  68                .mfilt1 = CCDC_NO_MEDIAN_FILTER1,
  69                .mfilt2 = CCDC_NO_MEDIAN_FILTER2,
  70                .alaw = {
  71                        .gama_wd = 2,
  72                },
  73                .blk_clamp = {
  74                        .sample_pixel = 1,
  75                        .dc_sub = 25
  76                },
  77                .col_pat_field0 = {
  78                        .olop = CCDC_GREEN_BLUE,
  79                        .olep = CCDC_BLUE,
  80                        .elop = CCDC_RED,
  81                        .elep = CCDC_GREEN_RED
  82                },
  83                .col_pat_field1 = {
  84                        .olop = CCDC_GREEN_BLUE,
  85                        .olep = CCDC_BLUE,
  86                        .elop = CCDC_RED,
  87                        .elep = CCDC_GREEN_RED
  88                },
  89        },
  90};
  91
  92
  93/* Object for CCDC ycbcr mode */
  94static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = {
  95        .win = CCDC_WIN_PAL,
  96        .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
  97        .frm_fmt = CCDC_FRMFMT_INTERLACED,
  98        .fid_pol = VPFE_PINPOL_POSITIVE,
  99        .vd_pol = VPFE_PINPOL_POSITIVE,
 100        .hd_pol = VPFE_PINPOL_POSITIVE,
 101        .bt656_enable = 1,
 102        .pix_order = CCDC_PIXORDER_CBYCRY,
 103        .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
 104};
 105
 106static enum vpfe_hw_if_type ccdc_if_type;
 107static void *__iomem ccdc_base_addr;
 108static int ccdc_addr_size;
 109
 110/* Raw Bayer formats */
 111static u32 ccdc_raw_bayer_pix_formats[] =
 112                {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
 113
 114/* Raw YUV formats */
 115static u32 ccdc_raw_yuv_pix_formats[] =
 116                {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
 117
 118/* register access routines */
 119static inline u32 regr(u32 offset)
 120{
 121        return __raw_readl(ccdc_base_addr + offset);
 122}
 123
 124static inline void regw(u32 val, u32 offset)
 125{
 126        __raw_writel(val, ccdc_base_addr + offset);
 127}
 128
 129static void ccdc_set_ccdc_base(void *addr, int size)
 130{
 131        ccdc_base_addr = addr;
 132        ccdc_addr_size = size;
 133}
 134
 135static void ccdc_enable(int en)
 136{
 137        unsigned int temp;
 138        temp = regr(SYNCEN);
 139        temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
 140        temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
 141        regw(temp, SYNCEN);
 142}
 143
 144static void ccdc_enable_output_to_sdram(int en)
 145{
 146        unsigned int temp;
 147        temp = regr(SYNCEN);
 148        temp &= (~(CCDC_SYNCEN_WEN_MASK));
 149        temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
 150        regw(temp, SYNCEN);
 151}
 152
 153static void ccdc_config_gain_offset(void)
 154{
 155        /* configure gain */
 156        regw(ccdc_hw_params_raw.gain.r_ye, RYEGAIN);
 157        regw(ccdc_hw_params_raw.gain.gr_cy, GRCYGAIN);
 158        regw(ccdc_hw_params_raw.gain.gb_g, GBGGAIN);
 159        regw(ccdc_hw_params_raw.gain.b_mg, BMGGAIN);
 160        /* configure offset */
 161        regw(ccdc_hw_params_raw.ccdc_offset, OFFSET);
 162}
 163
 164/*
 165 * ccdc_restore_defaults()
 166 * This function restore power on defaults in the ccdc registers
 167 */
 168static int ccdc_restore_defaults(void)
 169{
 170        int i;
 171
 172        dev_dbg(dev, "\nstarting ccdc_restore_defaults...");
 173        /* set all registers to zero */
 174        for (i = 0; i <= CCDC_REG_LAST; i += 4)
 175                regw(0, i);
 176
 177        /* now override the values with power on defaults in registers */
 178        regw(MODESET_DEFAULT, MODESET);
 179        /* no culling support */
 180        regw(CULH_DEFAULT, CULH);
 181        regw(CULV_DEFAULT, CULV);
 182        /* Set default Gain and Offset */
 183        ccdc_hw_params_raw.gain.r_ye = GAIN_DEFAULT;
 184        ccdc_hw_params_raw.gain.gb_g = GAIN_DEFAULT;
 185        ccdc_hw_params_raw.gain.gr_cy = GAIN_DEFAULT;
 186        ccdc_hw_params_raw.gain.b_mg = GAIN_DEFAULT;
 187        ccdc_config_gain_offset();
 188        regw(OUTCLIP_DEFAULT, OUTCLIP);
 189        regw(LSCCFG2_DEFAULT, LSCCFG2);
 190        /* select ccdc input */
 191        if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
 192                dev_dbg(dev, "\ncouldn't select ccdc input source");
 193                return -EFAULT;
 194        }
 195        /* select ccdc clock */
 196        if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
 197                dev_dbg(dev, "\ncouldn't enable ccdc clock");
 198                return -EFAULT;
 199        }
 200        dev_dbg(dev, "\nEnd of ccdc_restore_defaults...");
 201        return 0;
 202}
 203
 204static int ccdc_open(struct device *device)
 205{
 206        dev = device;
 207        return ccdc_restore_defaults();
 208}
 209
 210static int ccdc_close(struct device *device)
 211{
 212        /* disable clock */
 213        vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
 214        /* do nothing for now */
 215        return 0;
 216}
 217/*
 218 * ccdc_setwin()
 219 * This function will configure the window size to
 220 * be capture in CCDC reg.
 221 */
 222static void ccdc_setwin(struct v4l2_rect *image_win,
 223                        enum ccdc_frmfmt frm_fmt, int ppc)
 224{
 225        int horz_start, horz_nr_pixels;
 226        int vert_start, vert_nr_lines;
 227        int mid_img = 0;
 228
 229        dev_dbg(dev, "\nStarting ccdc_setwin...");
 230
 231        /*
 232         * ppc - per pixel count. indicates how many pixels per cell
 233         * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
 234         * raw capture this is 1
 235         */
 236        horz_start = image_win->left << (ppc - 1);
 237        horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
 238
 239        /* Writing the horizontal info into the registers */
 240        regw(horz_start, SPH);
 241        regw(horz_nr_pixels, NPH);
 242        vert_start = image_win->top;
 243
 244        if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
 245                vert_nr_lines = (image_win->height >> 1) - 1;
 246                vert_start >>= 1;
 247                /* Since first line doesn't have any data */
 248                vert_start += 1;
 249                /* configure VDINT0 and VDINT1 */
 250                regw(vert_start, VDINT0);
 251        } else {
 252                /* Since first line doesn't have any data */
 253                vert_start += 1;
 254                vert_nr_lines = image_win->height - 1;
 255                /* configure VDINT0 and VDINT1 */
 256                mid_img = vert_start + (image_win->height / 2);
 257                regw(vert_start, VDINT0);
 258                regw(mid_img, VDINT1);
 259        }
 260        regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
 261        regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
 262        regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
 263        dev_dbg(dev, "\nEnd of ccdc_setwin...");
 264}
 265
 266static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
 267{
 268        if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT ||
 269            ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) {
 270                dev_dbg(dev, "Invalid value of data shift\n");
 271                return -EINVAL;
 272        }
 273
 274        if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 ||
 275            ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) {
 276                dev_dbg(dev, "Invalid value of median filter1\n");
 277                return -EINVAL;
 278        }
 279
 280        if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 ||
 281            ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) {
 282                dev_dbg(dev, "Invalid value of median filter2\n");
 283                return -EINVAL;
 284        }
 285
 286        if ((ccdcparam->med_filt_thres < 0) ||
 287           (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
 288                dev_dbg(dev, "Invalid value of median filter thresold\n");
 289                return -EINVAL;
 290        }
 291
 292        if (ccdcparam->data_sz < CCDC_DATA_16BITS ||
 293            ccdcparam->data_sz > CCDC_DATA_8BITS) {
 294                dev_dbg(dev, "Invalid value of data size\n");
 295                return -EINVAL;
 296        }
 297
 298        if (ccdcparam->alaw.enable) {
 299                if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
 300                    ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
 301                        dev_dbg(dev, "Invalid value of ALAW\n");
 302                        return -EINVAL;
 303                }
 304        }
 305
 306        if (ccdcparam->blk_clamp.b_clamp_enable) {
 307                if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS ||
 308                    ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) {
 309                        dev_dbg(dev, "Invalid value of sample pixel\n");
 310                        return -EINVAL;
 311                }
 312                if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES ||
 313                    ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) {
 314                        dev_dbg(dev, "Invalid value of sample lines\n");
 315                        return -EINVAL;
 316                }
 317        }
 318        return 0;
 319}
 320
 321/* Parameter operations */
 322static int ccdc_set_params(void __user *params)
 323{
 324        struct ccdc_config_params_raw ccdc_raw_params;
 325        int x;
 326
 327        /* only raw module parameters can be set through the IOCTL */
 328        if (ccdc_if_type != VPFE_RAW_BAYER)
 329                return -EINVAL;
 330
 331        x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
 332        if (x) {
 333                dev_dbg(dev, "ccdc_set_params: error in copying ccdc"
 334                        "params, %d\n", x);
 335                return -EFAULT;
 336        }
 337
 338        if (!validate_ccdc_param(&ccdc_raw_params)) {
 339                memcpy(&ccdc_hw_params_raw.config_params,
 340                        &ccdc_raw_params,
 341                        sizeof(ccdc_raw_params));
 342                return 0;
 343        }
 344        return -EINVAL;
 345}
 346
 347/* This function will configure CCDC for YCbCr video capture */
 348static void ccdc_config_ycbcr(void)
 349{
 350        struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr;
 351        u32 temp;
 352
 353        /* first set the CCDC power on defaults values in all registers */
 354        dev_dbg(dev, "\nStarting ccdc_config_ycbcr...");
 355        ccdc_restore_defaults();
 356
 357        /* configure pixel format & video frame format */
 358        temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
 359                CCDC_INPUT_MODE_SHIFT) |
 360                ((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
 361                CCDC_FRM_FMT_SHIFT));
 362
 363        /* setup BT.656 sync mode */
 364        if (params->bt656_enable) {
 365                regw(CCDC_REC656IF_BT656_EN, REC656IF);
 366                /*
 367                 * configure the FID, VD, HD pin polarity fld,hd pol positive,
 368                 * vd negative, 8-bit pack mode
 369                 */
 370                temp |= CCDC_VD_POL_NEGATIVE;
 371        } else {                /* y/c external sync mode */
 372                temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
 373                        CCDC_FID_POL_SHIFT) |
 374                        ((params->hd_pol & CCDC_HD_POL_MASK) <<
 375                        CCDC_HD_POL_SHIFT) |
 376                        ((params->vd_pol & CCDC_VD_POL_MASK) <<
 377                        CCDC_VD_POL_SHIFT));
 378        }
 379
 380        /* pack the data to 8-bit */
 381        temp |= CCDC_DATA_PACK_ENABLE;
 382
 383        regw(temp, MODESET);
 384
 385        /* configure video window */
 386        ccdc_setwin(&params->win, params->frm_fmt, 2);
 387
 388        /* configure the order of y cb cr in SD-RAM */
 389        temp = (params->pix_order << CCDC_Y8POS_SHIFT);
 390        temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
 391        regw(temp, CCDCFG);
 392
 393        /*
 394         * configure the horizontal line offset. This is done by rounding up
 395         * width to a multiple of 16 pixels and multiply by two to account for
 396         * y:cb:cr 4:2:2 data
 397         */
 398        regw(((params->win.width * 2 + 31) >> 5), HSIZE);
 399
 400        /* configure the memory line offset */
 401        if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
 402                /* two fields are interleaved in memory */
 403                regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
 404        }
 405
 406        dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n");
 407}
 408
 409/*
 410 * ccdc_config_black_clamp()
 411 * configure parameters for Optical Black Clamp
 412 */
 413static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
 414{
 415        u32 val;
 416
 417        if (!bclamp->b_clamp_enable) {
 418                /* configure DCSub */
 419                regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
 420                regw(0x0000, CLAMP);
 421                return;
 422        }
 423        /* Enable the Black clamping, set sample lines and pixels */
 424        val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
 425              ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
 426                CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
 427        regw(val, CLAMP);
 428
 429        /* If Black clamping is enable then make dcsub 0 */
 430        val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
 431                        << CCDC_NUM_LINE_CALC_SHIFT;
 432        regw(val, DCSUB);
 433}
 434
 435/*
 436 * ccdc_config_black_compense()
 437 * configure parameters for Black Compensation
 438 */
 439static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
 440{
 441        u32 val;
 442
 443        val = (bcomp->b & CCDC_BLK_COMP_MASK) |
 444                ((bcomp->gb & CCDC_BLK_COMP_MASK) <<
 445                CCDC_BLK_COMP_GB_COMP_SHIFT);
 446        regw(val, BLKCMP1);
 447
 448        val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
 449                CCDC_BLK_COMP_GR_COMP_SHIFT) |
 450                ((bcomp->r & CCDC_BLK_COMP_MASK) <<
 451                CCDC_BLK_COMP_R_COMP_SHIFT);
 452        regw(val, BLKCMP0);
 453}
 454
 455/*
 456 * ccdc_write_dfc_entry()
 457 * write an entry in the dfc table.
 458 */
 459int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
 460{
 461/* TODO This is to be re-visited and adjusted */
 462#define DFC_WRITE_WAIT_COUNT    1000
 463        u32 val, count = DFC_WRITE_WAIT_COUNT;
 464
 465        regw(dfc->dft_corr_vert[index], DFCMEM0);
 466        regw(dfc->dft_corr_horz[index], DFCMEM1);
 467        regw(dfc->dft_corr_sub1[index], DFCMEM2);
 468        regw(dfc->dft_corr_sub2[index], DFCMEM3);
 469        regw(dfc->dft_corr_sub3[index], DFCMEM4);
 470        /* set WR bit to write */
 471        val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
 472        regw(val, DFCMEMCTL);
 473
 474        /*
 475         * Assume, it is very short. If we get an error, we need to
 476         * adjust this value
 477         */
 478        while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
 479                count--;
 480        /*
 481         * TODO We expect the count to be non-zero to be successful. Adjust
 482         * the count if write requires more time
 483         */
 484
 485        if (count) {
 486                dev_err(dev, "defect table write timeout !!!\n");
 487                return -1;
 488        }
 489        return 0;
 490}
 491
 492/*
 493 * ccdc_config_vdfc()
 494 * configure parameters for Vertical Defect Correction
 495 */
 496static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
 497{
 498        u32 val;
 499        int i;
 500
 501        /* Configure General Defect Correction. The table used is from IPIPE */
 502        val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
 503
 504        /* Configure Vertical Defect Correction if needed */
 505        if (!dfc->ver_dft_en) {
 506                /* Enable only General Defect Correction */
 507                regw(val, DFCCTL);
 508                return 0;
 509        }
 510
 511        if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
 512                return -EINVAL;
 513
 514        val |= CCDC_DFCCTL_VDFC_DISABLE;
 515        val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
 516                CCDC_DFCCTL_VDFCSL_SHIFT;
 517        val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
 518                CCDC_DFCCTL_VDFCUDA_SHIFT;
 519        val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
 520                CCDC_DFCCTL_VDFLSFT_SHIFT;
 521        regw(val , DFCCTL);
 522
 523        /* clear address ptr to offset 0 */
 524        val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
 525
 526        /* write defect table entries */
 527        for (i = 0; i < dfc->table_size; i++) {
 528                /* increment address for non zero index */
 529                if (i != 0)
 530                        val = CCDC_DFCMEMCTL_INC_ADDR;
 531                regw(val, DFCMEMCTL);
 532                if (ccdc_write_dfc_entry(i, dfc) < 0)
 533                        return -EFAULT;
 534        }
 535
 536        /* update saturation level and enable dfc */
 537        regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
 538        val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
 539                        CCDC_DFCCTL_VDFCEN_SHIFT);
 540        regw(val, DFCCTL);
 541        return 0;
 542}
 543
 544/*
 545 * ccdc_config_csc()
 546 * configure parameters for color space conversion
 547 * Each register CSCM0-7 has two values in S8Q5 format.
 548 */
 549static void ccdc_config_csc(struct ccdc_csc *csc)
 550{
 551        u32 val1, val2;
 552        int i;
 553
 554        if (!csc->enable)
 555                return;
 556
 557        /* Enable the CSC sub-module */
 558        regw(CCDC_CSC_ENABLE, CSCCTL);
 559
 560        /* Converting the co-eff as per the format of the register */
 561        for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
 562                if ((i % 2) == 0) {
 563                        /* CSCM - LSB */
 564                        val1 = (csc->coeff[i].integer &
 565                                CCDC_CSC_COEF_INTEG_MASK)
 566                                << CCDC_CSC_COEF_INTEG_SHIFT;
 567                        /*
 568                         * convert decimal part to binary. Use 2 decimal
 569                         * precision, user values range from .00 - 0.99
 570                         */
 571                        val1 |= (((csc->coeff[i].decimal &
 572                                CCDC_CSC_COEF_DECIMAL_MASK) *
 573                                CCDC_CSC_DEC_MAX) / 100);
 574                } else {
 575
 576                        /* CSCM - MSB */
 577                        val2 = (csc->coeff[i].integer &
 578                                CCDC_CSC_COEF_INTEG_MASK)
 579                                << CCDC_CSC_COEF_INTEG_SHIFT;
 580                        val2 |= (((csc->coeff[i].decimal &
 581                                 CCDC_CSC_COEF_DECIMAL_MASK) *
 582                                 CCDC_CSC_DEC_MAX) / 100);
 583                        val2 <<= CCDC_CSCM_MSB_SHIFT;
 584                        val2 |= val1;
 585                        regw(val2, (CSCM0 + ((i - 1) << 1)));
 586                }
 587        }
 588}
 589
 590/*
 591 * ccdc_config_color_patterns()
 592 * configure parameters for color patterns
 593 */
 594static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
 595                                       struct ccdc_col_pat *pat1)
 596{
 597        u32 val;
 598
 599        val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
 600                (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
 601                (pat1->elop << 12) | (pat1->elep << 14));
 602        regw(val, COLPTN);
 603}
 604
 605/* This function will configure CCDC for Raw mode image capture */
 606static int ccdc_config_raw(void)
 607{
 608        struct ccdc_params_raw *params = &ccdc_hw_params_raw;
 609        struct ccdc_config_params_raw *config_params =
 610                &ccdc_hw_params_raw.config_params;
 611        unsigned int val;
 612
 613        dev_dbg(dev, "\nStarting ccdc_config_raw...");
 614
 615        /* restore power on defaults to register */
 616        ccdc_restore_defaults();
 617
 618        /* CCDCFG register:
 619         * set CCD Not to swap input since input is RAW data
 620         * set FID detection function to Latch at V-Sync
 621         * set WENLOG - ccdc valid area to AND
 622         * set TRGSEL to WENBIT
 623         * set EXTRG to DISABLE
 624         * disable latching function on VSYNC - shadowed registers
 625         */
 626        regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
 627             CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
 628             CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
 629
 630        /*
 631         * Set VDHD direction to input,  input type to raw input
 632         * normal data polarity, do not use external WEN
 633         */
 634        val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
 635                CCDC_EXWEN_DISABLE);
 636
 637        /*
 638         * Configure the vertical sync polarity (MODESET.VDPOL), horizontal
 639         * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
 640         * frame format(progressive or interlace), & pixel format (Input mode)
 641         */
 642        val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
 643                ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
 644                ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
 645                ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
 646                ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
 647
 648        /* set pack for alaw compression */
 649        if ((config_params->data_sz == CCDC_DATA_8BITS) ||
 650             config_params->alaw.enable)
 651                val |= CCDC_DATA_PACK_ENABLE;
 652
 653        /* Configure for LPF */
 654        if (config_params->lpf_enable)
 655                val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
 656                        CCDC_LPF_SHIFT;
 657
 658        /* Configure the data shift */
 659        val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
 660                CCDC_DATASFT_SHIFT;
 661        regw(val , MODESET);
 662        dev_dbg(dev, "\nWriting 0x%x to MODESET...\n", val);
 663
 664        /* Configure the Median Filter threshold */
 665        regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
 666
 667        /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
 668        val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
 669                CCDC_CFA_MOSAIC;
 670
 671        /* Enable and configure aLaw register if needed */
 672        if (config_params->alaw.enable) {
 673                val |= (CCDC_ALAW_ENABLE |
 674                        ((config_params->alaw.gama_wd &
 675                        CCDC_ALAW_GAMA_WD_MASK) <<
 676                        CCDC_GAMMAWD_INPUT_SHIFT));
 677        }
 678
 679        /* Configure Median filter1 & filter2 */
 680        val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
 681                (config_params->mfilt2 << CCDC_MFILT2_SHIFT));
 682
 683        regw(val, GAMMAWD);
 684        dev_dbg(dev, "\nWriting 0x%x to GAMMAWD...\n", val);
 685
 686        /* configure video window */
 687        ccdc_setwin(&params->win, params->frm_fmt, 1);
 688
 689        /* Optical Clamp Averaging */
 690        ccdc_config_black_clamp(&config_params->blk_clamp);
 691
 692        /* Black level compensation */
 693        ccdc_config_black_compense(&config_params->blk_comp);
 694
 695        /* Vertical Defect Correction if needed */
 696        if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
 697                return -EFAULT;
 698
 699        /* color space conversion */
 700        ccdc_config_csc(&config_params->csc);
 701
 702        /* color pattern */
 703        ccdc_config_color_patterns(&config_params->col_pat_field0,
 704                                   &config_params->col_pat_field1);
 705
 706        /* Configure the Gain  & offset control */
 707        ccdc_config_gain_offset();
 708
 709        dev_dbg(dev, "\nWriting %x to COLPTN...\n", val);
 710
 711        /* Configure DATAOFST  register */
 712        val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
 713                CCDC_DATAOFST_H_SHIFT;
 714        val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
 715                CCDC_DATAOFST_V_SHIFT;
 716        regw(val, DATAOFST);
 717
 718        /* configuring HSIZE register */
 719        val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
 720                CCDC_HSIZE_FLIP_SHIFT;
 721
 722        /* If pack 8 is enable then 1 pixel will take 1 byte */
 723        if ((config_params->data_sz == CCDC_DATA_8BITS) ||
 724             config_params->alaw.enable) {
 725                val |= (((params->win.width) + 31) >> 5) &
 726                        CCDC_HSIZE_VAL_MASK;
 727
 728                /* adjust to multiple of 32 */
 729                dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
 730                       (((params->win.width) + 31) >> 5) &
 731                        CCDC_HSIZE_VAL_MASK);
 732        } else {
 733                /* else one pixel will take 2 byte */
 734                val |= (((params->win.width * 2) + 31) >> 5) &
 735                        CCDC_HSIZE_VAL_MASK;
 736
 737                dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n",
 738                       (((params->win.width * 2) + 31) >> 5) &
 739                        CCDC_HSIZE_VAL_MASK);
 740        }
 741        regw(val, HSIZE);
 742
 743        /* Configure SDOFST register */
 744        if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
 745                if (params->image_invert_enable) {
 746                        /* For interlace inverse mode */
 747                        regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
 748                        dev_dbg(dev, "\nWriting %x to SDOFST...\n",
 749                                CCDC_SDOFST_INTERLACE_INVERSE);
 750                } else {
 751                        /* For interlace non inverse mode */
 752                        regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
 753                        dev_dbg(dev, "\nWriting %x to SDOFST...\n",
 754                                CCDC_SDOFST_INTERLACE_NORMAL);
 755                }
 756        } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
 757                if (params->image_invert_enable) {
 758                        /* For progessive inverse mode */
 759                        regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
 760                        dev_dbg(dev, "\nWriting %x to SDOFST...\n",
 761                                CCDC_SDOFST_PROGRESSIVE_INVERSE);
 762                } else {
 763                        /* For progessive non inverse mode */
 764                        regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
 765                        dev_dbg(dev, "\nWriting %x to SDOFST...\n",
 766                                CCDC_SDOFST_PROGRESSIVE_NORMAL);
 767                }
 768        }
 769        dev_dbg(dev, "\nend of ccdc_config_raw...");
 770        return 0;
 771}
 772
 773static int ccdc_configure(void)
 774{
 775        if (ccdc_if_type == VPFE_RAW_BAYER)
 776                return ccdc_config_raw();
 777        else
 778                ccdc_config_ycbcr();
 779        return 0;
 780}
 781
 782static int ccdc_set_buftype(enum ccdc_buftype buf_type)
 783{
 784        if (ccdc_if_type == VPFE_RAW_BAYER)
 785                ccdc_hw_params_raw.buf_type = buf_type;
 786        else
 787                ccdc_hw_params_ycbcr.buf_type = buf_type;
 788        return 0;
 789}
 790static enum ccdc_buftype ccdc_get_buftype(void)
 791{
 792        if (ccdc_if_type == VPFE_RAW_BAYER)
 793                return ccdc_hw_params_raw.buf_type;
 794        return ccdc_hw_params_ycbcr.buf_type;
 795}
 796
 797static int ccdc_enum_pix(u32 *pix, int i)
 798{
 799        int ret = -EINVAL;
 800        if (ccdc_if_type == VPFE_RAW_BAYER) {
 801                if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
 802                        *pix = ccdc_raw_bayer_pix_formats[i];
 803                        ret = 0;
 804                }
 805        } else {
 806                if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
 807                        *pix = ccdc_raw_yuv_pix_formats[i];
 808                        ret = 0;
 809                }
 810        }
 811        return ret;
 812}
 813
 814static int ccdc_set_pixel_format(u32 pixfmt)
 815{
 816        struct ccdc_a_law *alaw =
 817                &ccdc_hw_params_raw.config_params.alaw;
 818
 819        if (ccdc_if_type == VPFE_RAW_BAYER) {
 820                ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW;
 821                if (pixfmt == V4L2_PIX_FMT_SBGGR8)
 822                        alaw->enable = 1;
 823                else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
 824                        return -EINVAL;
 825        } else {
 826                if (pixfmt == V4L2_PIX_FMT_YUYV)
 827                        ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
 828                else if (pixfmt == V4L2_PIX_FMT_UYVY)
 829                        ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
 830                else
 831                        return -EINVAL;
 832        }
 833        return 0;
 834}
 835static u32 ccdc_get_pixel_format(void)
 836{
 837        struct ccdc_a_law *alaw =
 838                &ccdc_hw_params_raw.config_params.alaw;
 839        u32 pixfmt;
 840
 841        if (ccdc_if_type == VPFE_RAW_BAYER)
 842                if (alaw->enable)
 843                        pixfmt = V4L2_PIX_FMT_SBGGR8;
 844                else
 845                        pixfmt = V4L2_PIX_FMT_SBGGR16;
 846        else {
 847                if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
 848                        pixfmt = V4L2_PIX_FMT_YUYV;
 849                else
 850                        pixfmt = V4L2_PIX_FMT_UYVY;
 851        }
 852        return pixfmt;
 853}
 854static int ccdc_set_image_window(struct v4l2_rect *win)
 855{
 856        if (ccdc_if_type == VPFE_RAW_BAYER)
 857                ccdc_hw_params_raw.win = *win;
 858        else
 859                ccdc_hw_params_ycbcr.win = *win;
 860        return 0;
 861}
 862
 863static void ccdc_get_image_window(struct v4l2_rect *win)
 864{
 865        if (ccdc_if_type == VPFE_RAW_BAYER)
 866                *win = ccdc_hw_params_raw.win;
 867        else
 868                *win = ccdc_hw_params_ycbcr.win;
 869}
 870
 871static unsigned int ccdc_get_line_length(void)
 872{
 873        struct ccdc_config_params_raw *config_params =
 874                &ccdc_hw_params_raw.config_params;
 875        unsigned int len;
 876
 877        if (ccdc_if_type == VPFE_RAW_BAYER) {
 878                if ((config_params->alaw.enable) ||
 879                    (config_params->data_sz == CCDC_DATA_8BITS))
 880                        len = ccdc_hw_params_raw.win.width;
 881                else
 882                        len = ccdc_hw_params_raw.win.width * 2;
 883        } else
 884                len = ccdc_hw_params_ycbcr.win.width * 2;
 885        return ALIGN(len, 32);
 886}
 887
 888static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
 889{
 890        if (ccdc_if_type == VPFE_RAW_BAYER)
 891                ccdc_hw_params_raw.frm_fmt = frm_fmt;
 892        else
 893                ccdc_hw_params_ycbcr.frm_fmt = frm_fmt;
 894        return 0;
 895}
 896
 897static enum ccdc_frmfmt ccdc_get_frame_format(void)
 898{
 899        if (ccdc_if_type == VPFE_RAW_BAYER)
 900                return ccdc_hw_params_raw.frm_fmt;
 901        else
 902                return ccdc_hw_params_ycbcr.frm_fmt;
 903}
 904
 905static int ccdc_getfid(void)
 906{
 907        return  (regr(MODESET) >> 15) & 1;
 908}
 909
 910/* misc operations */
 911static inline void ccdc_setfbaddr(unsigned long addr)
 912{
 913        regw((addr >> 21) & 0x007f, STADRH);
 914        regw((addr >> 5) & 0x0ffff, STADRL);
 915}
 916
 917static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
 918{
 919        ccdc_if_type = params->if_type;
 920
 921        switch (params->if_type) {
 922        case VPFE_BT656:
 923        case VPFE_YCBCR_SYNC_16:
 924        case VPFE_YCBCR_SYNC_8:
 925                ccdc_hw_params_ycbcr.vd_pol = params->vdpol;
 926                ccdc_hw_params_ycbcr.hd_pol = params->hdpol;
 927                break;
 928        default:
 929                /* TODO add support for raw bayer here */
 930                return -EINVAL;
 931        }
 932        return 0;
 933}
 934
 935static struct ccdc_hw_device ccdc_hw_dev = {
 936        .name = "DM355 CCDC",
 937        .owner = THIS_MODULE,
 938        .hw_ops = {
 939                .open = ccdc_open,
 940                .close = ccdc_close,
 941                .set_ccdc_base = ccdc_set_ccdc_base,
 942                .enable = ccdc_enable,
 943                .enable_out_to_sdram = ccdc_enable_output_to_sdram,
 944                .set_hw_if_params = ccdc_set_hw_if_params,
 945                .set_params = ccdc_set_params,
 946                .configure = ccdc_configure,
 947                .set_buftype = ccdc_set_buftype,
 948                .get_buftype = ccdc_get_buftype,
 949                .enum_pix = ccdc_enum_pix,
 950                .set_pixel_format = ccdc_set_pixel_format,
 951                .get_pixel_format = ccdc_get_pixel_format,
 952                .set_frame_format = ccdc_set_frame_format,
 953                .get_frame_format = ccdc_get_frame_format,
 954                .set_image_window = ccdc_set_image_window,
 955                .get_image_window = ccdc_get_image_window,
 956                .get_line_length = ccdc_get_line_length,
 957                .setfbaddr = ccdc_setfbaddr,
 958                .getfid = ccdc_getfid,
 959        },
 960};
 961
 962static int dm355_ccdc_init(void)
 963{
 964        printk(KERN_NOTICE "dm355_ccdc_init\n");
 965        if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
 966                return -1;
 967        printk(KERN_NOTICE "%s is registered with vpfe.\n",
 968                ccdc_hw_dev.name);
 969        return 0;
 970}
 971
 972static void dm355_ccdc_exit(void)
 973{
 974        vpfe_unregister_ccdc_device(&ccdc_hw_dev);
 975}
 976
 977module_init(dm355_ccdc_init);
 978module_exit(dm355_ccdc_exit);
 979
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.