linux/drivers/staging/media/davinci_vpfe/dm365_isif.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Texas Instruments Inc
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public License as
   6 * published by the Free Software Foundation version 2.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public License
  14 * along with this program; if not, write to the Free Software
  15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  16 *
  17 * Contributors:
  18 *      Manjunath Hadli <manjunath.hadli@ti.com>
  19 *      Prabhakar Lad <prabhakar.lad@ti.com>
  20 */
  21
  22#include "dm365_isif.h"
  23#include "vpfe_mc_capture.h"
  24
  25#define MAX_WIDTH       4096
  26#define MAX_HEIGHT      4096
  27
  28static const unsigned int isif_fmts[] = {
  29        V4L2_MBUS_FMT_YUYV8_2X8,
  30        V4L2_MBUS_FMT_UYVY8_2X8,
  31        V4L2_MBUS_FMT_YUYV8_1X16,
  32        V4L2_MBUS_FMT_YUYV10_1X20,
  33        V4L2_MBUS_FMT_SGRBG12_1X12,
  34        V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8,
  35        V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
  36};
  37
  38#define ISIF_COLPTN_R_Ye        0x0
  39#define ISIF_COLPTN_Gr_Cy       0x1
  40#define ISIF_COLPTN_Gb_G        0x2
  41#define ISIF_COLPTN_B_Mg        0x3
  42
  43#define ISIF_CCOLP_CP01_0       0
  44#define ISIF_CCOLP_CP03_2       2
  45#define ISIF_CCOLP_CP05_4       4
  46#define ISIF_CCOLP_CP07_6       6
  47#define ISIF_CCOLP_CP11_0       8
  48#define ISIF_CCOLP_CP13_2       10
  49#define ISIF_CCOLP_CP15_4       12
  50#define ISIF_CCOLP_CP17_6       14
  51
  52static const u32 isif_sgrbg_pattern =
  53        ISIF_COLPTN_Gr_Cy <<  ISIF_CCOLP_CP01_0 |
  54        ISIF_COLPTN_R_Ye  << ISIF_CCOLP_CP03_2 |
  55        ISIF_COLPTN_B_Mg  << ISIF_CCOLP_CP05_4 |
  56        ISIF_COLPTN_Gb_G  << ISIF_CCOLP_CP07_6 |
  57        ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP11_0 |
  58        ISIF_COLPTN_R_Ye  << ISIF_CCOLP_CP13_2 |
  59        ISIF_COLPTN_B_Mg  << ISIF_CCOLP_CP15_4 |
  60        ISIF_COLPTN_Gb_G  << ISIF_CCOLP_CP17_6;
  61
  62static const u32 isif_srggb_pattern =
  63        ISIF_COLPTN_R_Ye  << ISIF_CCOLP_CP01_0 |
  64        ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP03_2 |
  65        ISIF_COLPTN_Gb_G  << ISIF_CCOLP_CP05_4 |
  66        ISIF_COLPTN_B_Mg  << ISIF_CCOLP_CP07_6 |
  67        ISIF_COLPTN_R_Ye  << ISIF_CCOLP_CP11_0 |
  68        ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP13_2 |
  69        ISIF_COLPTN_Gb_G  << ISIF_CCOLP_CP15_4 |
  70        ISIF_COLPTN_B_Mg  << ISIF_CCOLP_CP17_6;
  71
  72static inline u32 isif_read(void *__iomem base_addr, u32 offset)
  73{
  74        return readl(base_addr + offset);
  75}
  76
  77static inline void isif_write(void *__iomem base_addr, u32 val, u32 offset)
  78{
  79        writel(val, base_addr + offset);
  80}
  81
  82static inline u32 isif_merge(void *__iomem base_addr, u32 mask, u32 val,
  83                             u32 offset)
  84{
  85        u32 new_val = (isif_read(base_addr, offset) & ~mask) | (val & mask);
  86
  87        isif_write(base_addr, new_val, offset);
  88
  89        return new_val;
  90}
  91
  92static void isif_enable_output_to_sdram(struct vpfe_isif_device *isif, int en)
  93{
  94        isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_WEN_MASK,
  95                   en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
  96}
  97
  98static inline void
  99isif_regw_lin_tbl(struct vpfe_isif_device *isif, u32 val, u32 offset, int i)
 100{
 101        if (!i)
 102                writel(val, isif->isif_cfg.linear_tbl0_addr + offset);
 103        else
 104                writel(val, isif->isif_cfg.linear_tbl1_addr + offset);
 105}
 106
 107static void isif_disable_all_modules(struct vpfe_isif_device *isif)
 108{
 109        /* disable BC */
 110        isif_write(isif->isif_cfg.base_addr, 0, CLAMPCFG);
 111        /* disable vdfc */
 112        isif_write(isif->isif_cfg.base_addr, 0, DFCCTL);
 113        /* disable CSC */
 114        isif_write(isif->isif_cfg.base_addr, 0, CSCCTL);
 115        /* disable linearization */
 116        isif_write(isif->isif_cfg.base_addr, 0, LINCFG0);
 117}
 118
 119static void isif_enable(struct vpfe_isif_device *isif, int en)
 120{
 121        if (!en)
 122                /* Before disable isif, disable all ISIF modules */
 123                isif_disable_all_modules(isif);
 124
 125        /*
 126         * wait for next VD. Assume lowest scan rate is 12 Hz. So
 127         * 100 msec delay is good enough
 128         */
 129        msleep(100);
 130        isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_VDHDEN_MASK,
 131                   en, SYNCEN);
 132}
 133
 134/*
 135 * ISIF helper functions
 136 */
 137
 138#define DM365_ISIF_MDFS_OFFSET          15
 139#define DM365_ISIF_MDFS_MASK            0x1
 140
 141/* get field id in isif hardware */
 142enum v4l2_field vpfe_isif_get_fid(struct vpfe_device *vpfe_dev)
 143{
 144        struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif;
 145        u32 field_status;
 146
 147        field_status = isif_read(isif->isif_cfg.base_addr, MODESET);
 148        field_status = (field_status >> DM365_ISIF_MDFS_OFFSET) &
 149                        DM365_ISIF_MDFS_MASK;
 150        return field_status;
 151}
 152
 153static int
 154isif_set_pixel_format(struct vpfe_isif_device *isif, unsigned int pixfmt)
 155{
 156        if (isif->formats[ISIF_PAD_SINK].code == V4L2_MBUS_FMT_SGRBG12_1X12) {
 157                if (pixfmt == V4L2_PIX_FMT_SBGGR16)
 158                        isif->isif_cfg.data_pack = ISIF_PACK_16BIT;
 159                else if ((pixfmt == V4L2_PIX_FMT_SGRBG10DPCM8) ||
 160                                (pixfmt == V4L2_PIX_FMT_SGRBG10ALAW8))
 161                        isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
 162                else
 163                        return -EINVAL;
 164
 165                isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW;
 166                isif->isif_cfg.bayer.v4l2_pix_fmt = pixfmt;
 167        } else {
 168                if (pixfmt == V4L2_PIX_FMT_YUYV)
 169                        isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_YCBYCR;
 170                else if (pixfmt == V4L2_PIX_FMT_UYVY)
 171                        isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY;
 172                else
 173                        return -EINVAL;
 174
 175                isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
 176                isif->isif_cfg.ycbcr.v4l2_pix_fmt = pixfmt;
 177        }
 178
 179        return 0;
 180}
 181
 182static int
 183isif_set_frame_format(struct vpfe_isif_device *isif,
 184                      enum isif_frmfmt frm_fmt)
 185{
 186        if (isif->formats[ISIF_PAD_SINK].code == V4L2_MBUS_FMT_SGRBG12_1X12)
 187                isif->isif_cfg.bayer.frm_fmt = frm_fmt;
 188        else
 189                isif->isif_cfg.ycbcr.frm_fmt = frm_fmt;
 190
 191        return 0;
 192}
 193
 194static int isif_set_image_window(struct vpfe_isif_device *isif)
 195{
 196        struct v4l2_rect *win = &isif->crop;
 197
 198        if (isif->formats[ISIF_PAD_SINK].code == V4L2_MBUS_FMT_SGRBG12_1X12) {
 199                isif->isif_cfg.bayer.win.top = win->top;
 200                isif->isif_cfg.bayer.win.left = win->left;
 201                isif->isif_cfg.bayer.win.width = win->width;
 202                isif->isif_cfg.bayer.win.height = win->height;
 203                return 0;
 204        }
 205        isif->isif_cfg.ycbcr.win.top = win->top;
 206        isif->isif_cfg.ycbcr.win.left = win->left;
 207        isif->isif_cfg.ycbcr.win.width = win->width;
 208        isif->isif_cfg.ycbcr.win.height = win->height;
 209
 210        return 0;
 211}
 212
 213static int
 214isif_set_buftype(struct vpfe_isif_device *isif, enum isif_buftype buf_type)
 215{
 216        if (isif->formats[ISIF_PAD_SINK].code == V4L2_MBUS_FMT_SGRBG12_1X12)
 217                isif->isif_cfg.bayer.buf_type = buf_type;
 218        else
 219                isif->isif_cfg.ycbcr.buf_type = buf_type;
 220
 221        return 0;
 222}
 223
 224/* configure format in isif hardware */
 225static int
 226isif_config_format(struct vpfe_device *vpfe_dev, unsigned int pad)
 227{
 228        struct vpfe_isif_device *vpfe_isif = &vpfe_dev->vpfe_isif;
 229        enum isif_frmfmt frm_fmt = ISIF_FRMFMT_INTERLACED;
 230        struct v4l2_pix_format format;
 231        int ret = 0;
 232
 233        v4l2_fill_pix_format(&format, &vpfe_dev->vpfe_isif.formats[pad]);
 234        mbus_to_pix(&vpfe_dev->vpfe_isif.formats[pad], &format);
 235
 236        if (isif_set_pixel_format(vpfe_isif, format.pixelformat) < 0) {
 237                v4l2_err(&vpfe_dev->v4l2_dev,
 238                         "Failed to set pixel format in isif\n");
 239                return -EINVAL;
 240        }
 241
 242        /* call for s_crop will override these values */
 243        vpfe_isif->crop.left = 0;
 244        vpfe_isif->crop.top = 0;
 245        vpfe_isif->crop.width = format.width;
 246        vpfe_isif->crop.height = format.height;
 247
 248        /* configure the image window */
 249        isif_set_image_window(vpfe_isif);
 250
 251        switch (vpfe_dev->vpfe_isif.formats[pad].field) {
 252        case V4L2_FIELD_INTERLACED:
 253                /* do nothing, since it is default */
 254                ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_INTERLEAVED);
 255                break;
 256
 257        case V4L2_FIELD_NONE:
 258                frm_fmt = ISIF_FRMFMT_PROGRESSIVE;
 259                /* buffer type only applicable for interlaced scan */
 260                break;
 261
 262        case V4L2_FIELD_SEQ_TB:
 263                ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_SEPARATED);
 264                break;
 265
 266        default:
 267                return -EINVAL;
 268        }
 269
 270        /* set the frame format */
 271        if (!ret)
 272                ret = isif_set_frame_format(vpfe_isif, frm_fmt);
 273
 274        return ret;
 275}
 276
 277/*
 278 * isif_try_format() - Try video format on a pad
 279 * @isif: VPFE isif device
 280 * @fh: V4L2 subdev file handle
 281 * @fmt: pointer to v4l2 subdev format structure
 282 */
 283static void
 284isif_try_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh,
 285                struct v4l2_subdev_format *fmt)
 286{
 287        unsigned int width = fmt->format.width;
 288        unsigned int height = fmt->format.height;
 289        unsigned int i;
 290
 291        for (i = 0; i < ARRAY_SIZE(isif_fmts); i++) {
 292                if (fmt->format.code == isif_fmts[i])
 293                        break;
 294        }
 295
 296        /* If not found, use YUYV8_2x8 as default */
 297        if (i >= ARRAY_SIZE(isif_fmts))
 298                fmt->format.code = V4L2_MBUS_FMT_YUYV8_2X8;
 299
 300        /* Clamp the size. */
 301        fmt->format.width = clamp_t(u32, width, 32, MAX_WIDTH);
 302        fmt->format.height = clamp_t(u32, height, 32, MAX_HEIGHT);
 303
 304        /* The data formatter truncates the number of horizontal output
 305         * pixels to a multiple of 16. To avoid clipping data, allow
 306         * callers to request an output size bigger than the input size
 307         * up to the nearest multiple of 16.
 308         */
 309        if (fmt->pad == ISIF_PAD_SOURCE)
 310                fmt->format.width &= ~15;
 311}
 312
 313/*
 314 * vpfe_isif_buffer_isr() - isif module non-progressive buffer scheduling isr
 315 * @isif: Pointer to isif subdevice.
 316 */
 317void vpfe_isif_buffer_isr(struct vpfe_isif_device *isif)
 318{
 319        struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
 320        struct vpfe_video_device *video = &isif->video_out;
 321        enum v4l2_field field;
 322        int fid;
 323
 324        if (!video->started)
 325                return;
 326
 327        field = video->fmt.fmt.pix.field;
 328
 329        if (field == V4L2_FIELD_NONE) {
 330                /* handle progressive frame capture */
 331                if (video->cur_frm != video->next_frm)
 332                        vpfe_video_process_buffer_complete(video);
 333                return;
 334        }
 335
 336        /* interlaced or TB capture check which field we
 337         * are in hardware
 338         */
 339        fid = vpfe_isif_get_fid(vpfe_dev);
 340
 341        /* switch the software maintained field id */
 342        video->field_id ^= 1;
 343        if (fid == video->field_id) {
 344                /* we are in-sync here,continue */
 345                if (fid == 0) {
 346                        /*
 347                         * One frame is just being captured. If the
 348                         * next frame is available, release the current
 349                         * frame and move on
 350                         */
 351                        if (video->cur_frm != video->next_frm)
 352                                vpfe_video_process_buffer_complete(video);
 353                        /*
 354                         * based on whether the two fields are stored
 355                         * interleavely or separately in memory,
 356                         * reconfigure the ISIF memory address
 357                         */
 358                        if (field == V4L2_FIELD_SEQ_TB)
 359                                vpfe_video_schedule_bottom_field(video);
 360                        return;
 361                }
 362                /*
 363                 * if one field is just being captured configure
 364                 * the next frame get the next frame from the
 365                 * empty queue if no frame is available hold on
 366                 * to the current buffer
 367                 */
 368                spin_lock(&video->dma_queue_lock);
 369                if (!list_empty(&video->dma_queue) &&
 370                video->cur_frm == video->next_frm)
 371                        vpfe_video_schedule_next_buffer(video);
 372                spin_unlock(&video->dma_queue_lock);
 373        } else if (fid == 0) {
 374                /*
 375                 * out of sync. Recover from any hardware out-of-sync.
 376                 * May loose one frame
 377                 */
 378                video->field_id = fid;
 379        }
 380}
 381
 382/*
 383 * vpfe_isif_vidint1_isr() - ISIF module progressive buffer scheduling isr
 384 * @isif: Pointer to isif subdevice.
 385 */
 386void vpfe_isif_vidint1_isr(struct vpfe_isif_device *isif)
 387{
 388        struct vpfe_video_device *video = &isif->video_out;
 389
 390        if (!video->started)
 391                return;
 392
 393        spin_lock(&video->dma_queue_lock);
 394        if (video->fmt.fmt.pix.field == V4L2_FIELD_NONE &&
 395            !list_empty(&video->dma_queue) && video->cur_frm == video->next_frm)
 396                vpfe_video_schedule_next_buffer(video);
 397
 398        spin_unlock(&video->dma_queue_lock);
 399}
 400
 401/*
 402 * VPFE video operations
 403 */
 404
 405static int isif_video_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
 406{
 407        struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif;
 408
 409        isif_write(isif->isif_cfg.base_addr, (addr >> 21) &
 410                ISIF_CADU_BITS, CADU);
 411        isif_write(isif->isif_cfg.base_addr, (addr >> 5) &
 412                ISIF_CADL_BITS, CADL);
 413
 414        return 0;
 415}
 416
 417static const struct vpfe_video_operations isif_video_ops = {
 418        .queue = isif_video_queue,
 419};
 420
 421/*
 422 * V4L2 subdev operations
 423 */
 424
 425/* Parameter operations */
 426static int isif_get_params(struct v4l2_subdev *sd, void *params)
 427{
 428        struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
 429
 430        /* only raw module parameters can be set through the IOCTL */
 431        if (isif->formats[ISIF_PAD_SINK].code != V4L2_MBUS_FMT_SGRBG12_1X12)
 432                return -EINVAL;
 433        memcpy(params, &isif->isif_cfg.bayer.config_params,
 434                        sizeof(isif->isif_cfg.bayer.config_params));
 435        return 0;
 436}
 437
 438static int isif_validate_df_csc_params(struct vpfe_isif_df_csc *df_csc)
 439{
 440        struct vpfe_isif_color_space_conv *csc;
 441        int err = -EINVAL;
 442        int csc_df_en;
 443        int i;
 444
 445        if (!df_csc->df_or_csc) {
 446                /* csc configuration */
 447                csc = &df_csc->csc;
 448                if (csc->en) {
 449                        csc_df_en = 1;
 450                        for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++)
 451                                if (csc->coeff[i].integer >
 452                                    ISIF_CSC_COEF_INTEG_MASK ||
 453                                    csc->coeff[i].decimal >
 454                                    ISIF_CSC_COEF_DECIMAL_MASK) {
 455                                        pr_err("Invalid CSC coefficients\n");
 456                                        return err;
 457                                }
 458                }
 459        }
 460        if (df_csc->start_pix > ISIF_DF_CSC_SPH_MASK) {
 461                pr_err("Invalid df_csc start pix value\n");
 462                return err;
 463        }
 464
 465        if (df_csc->num_pixels > ISIF_DF_NUMPIX) {
 466                pr_err("Invalid df_csc num pixels value\n");
 467                return err;
 468        }
 469
 470        if (df_csc->start_line > ISIF_DF_CSC_LNH_MASK) {
 471                pr_err("Invalid df_csc start_line value\n");
 472                return err;
 473        }
 474
 475        if (df_csc->num_lines > ISIF_DF_NUMLINES) {
 476                pr_err("Invalid df_csc num_lines value\n");
 477                return err;
 478        }
 479
 480        return 0;
 481}
 482
 483#define DM365_ISIF_MAX_VDFLSFT          4
 484#define DM365_ISIF_MAX_VDFSLV           4095
 485#define DM365_ISIF_MAX_DFCMEM0          0x1fff
 486#define DM365_ISIF_MAX_DFCMEM1          0x1fff
 487
 488static int isif_validate_dfc_params(struct vpfe_isif_dfc *dfc)
 489{
 490        int err = -EINVAL;
 491        int i;
 492
 493        if (!dfc->en)
 494                return 0;
 495
 496        if (dfc->corr_whole_line > 1) {
 497                pr_err("Invalid corr_whole_line value\n");
 498                return err;
 499        }
 500
 501        if (dfc->def_level_shift > DM365_ISIF_MAX_VDFLSFT) {
 502                pr_err("Invalid def_level_shift value\n");
 503                return err;
 504        }
 505
 506        if (dfc->def_sat_level > DM365_ISIF_MAX_VDFSLV) {
 507                pr_err("Invalid def_sat_level value\n");
 508                return err;
 509        }
 510
 511        if (!dfc->num_vdefects ||
 512            dfc->num_vdefects > VPFE_ISIF_VDFC_TABLE_SIZE) {
 513                pr_err("Invalid num_vdefects value\n");
 514                return err;
 515        }
 516
 517        for (i = 0; i < VPFE_ISIF_VDFC_TABLE_SIZE; i++) {
 518                if (dfc->table[i].pos_vert > DM365_ISIF_MAX_DFCMEM0) {
 519                        pr_err("Invalid pos_vert value\n");
 520                        return err;
 521                }
 522                if (dfc->table[i].pos_horz > DM365_ISIF_MAX_DFCMEM1) {
 523                        pr_err("Invalid pos_horz value\n");
 524                        return err;
 525                }
 526        }
 527
 528        return 0;
 529}
 530
 531#define DM365_ISIF_MAX_CLVRV                    0xfff
 532#define DM365_ISIF_MAX_CLDC                     0x1fff
 533#define DM365_ISIF_MAX_CLHSH                    0x1fff
 534#define DM365_ISIF_MAX_CLHSV                    0x1fff
 535#define DM365_ISIF_MAX_CLVSH                    0x1fff
 536#define DM365_ISIF_MAX_CLVSV                    0x1fff
 537#define DM365_ISIF_MAX_HEIGHT_BLACK_REGION      0x1fff
 538
 539static int isif_validate_bclamp_params(struct vpfe_isif_black_clamp *bclamp)
 540{
 541        int err = -EINVAL;
 542
 543        if (bclamp->dc_offset > DM365_ISIF_MAX_CLDC) {
 544                pr_err("Invalid bclamp dc_offset value\n");
 545                return err;
 546        }
 547        if (!bclamp->en)
 548                return 0;
 549        if (bclamp->horz.clamp_pix_limit > 1) {
 550                pr_err("Invalid bclamp horz clamp_pix_limit value\n");
 551                return err;
 552        }
 553        if (bclamp->horz.win_count_calc < 1 ||
 554                        bclamp->horz.win_count_calc > 32) {
 555                pr_err("Invalid bclamp horz win_count_calc value\n");
 556                return err;
 557        }
 558        if (bclamp->horz.win_start_h_calc > DM365_ISIF_MAX_CLHSH) {
 559                pr_err("Invalid bclamp win_start_v_calc value\n");
 560                return err;
 561        }
 562
 563        if (bclamp->horz.win_start_v_calc > DM365_ISIF_MAX_CLHSV) {
 564                pr_err("Invalid bclamp win_start_v_calc value\n");
 565                return err;
 566        }
 567        if (bclamp->vert.reset_clamp_val > DM365_ISIF_MAX_CLVRV) {
 568                pr_err("Invalid bclamp reset_clamp_val value\n");
 569                return err;
 570        }
 571        if (bclamp->vert.ob_v_sz_calc > DM365_ISIF_MAX_HEIGHT_BLACK_REGION) {
 572                pr_err("Invalid bclamp ob_v_sz_calc value\n");
 573                return err;
 574        }
 575        if (bclamp->vert.ob_start_h > DM365_ISIF_MAX_CLVSH) {
 576                pr_err("Invalid bclamp ob_start_h value\n");
 577                return err;
 578        }
 579        if (bclamp->vert.ob_start_v > DM365_ISIF_MAX_CLVSV) {
 580                pr_err("Invalid bclamp ob_start_h value\n");
 581                return err;
 582        }
 583        return 0;
 584}
 585
 586static int
 587isif_validate_raw_params(struct vpfe_isif_raw_config *params)
 588{
 589        int ret;
 590
 591        ret = isif_validate_df_csc_params(&params->df_csc);
 592        if (ret)
 593                return ret;
 594        ret = isif_validate_dfc_params(&params->dfc);
 595        if (ret)
 596                return ret;
 597        ret = isif_validate_bclamp_params(&params->bclamp);
 598        return ret;
 599}
 600
 601static int isif_set_params(struct v4l2_subdev *sd, void *params)
 602{
 603        struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
 604        struct vpfe_isif_raw_config isif_raw_params;
 605        int ret = -EINVAL;
 606
 607        /* only raw module parameters can be set through the IOCTL */
 608        if (isif->formats[ISIF_PAD_SINK].code != V4L2_MBUS_FMT_SGRBG12_1X12)
 609                return ret;
 610
 611        memcpy(&isif_raw_params, params, sizeof(isif_raw_params));
 612        if (!isif_validate_raw_params(&isif_raw_params)) {
 613                memcpy(&isif->isif_cfg.bayer.config_params, &isif_raw_params,
 614                        sizeof(isif_raw_params));
 615                ret = 0;
 616        }
 617        return ret;
 618}
 619/*
 620 * isif_ioctl() - isif module private ioctl's
 621 * @sd: VPFE isif V4L2 subdevice
 622 * @cmd: ioctl command
 623 * @arg: ioctl argument
 624 *
 625 * Return 0 on success or a negative error code otherwise.
 626 */
 627static long isif_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 628{
 629        int ret;
 630
 631        switch (cmd) {
 632        case VIDIOC_VPFE_ISIF_S_RAW_PARAMS:
 633                ret = isif_set_params(sd, arg);
 634                break;
 635
 636        case VIDIOC_VPFE_ISIF_G_RAW_PARAMS:
 637                ret = isif_get_params(sd, arg);
 638                break;
 639
 640        default:
 641                ret = -ENOIOCTLCMD;
 642        }
 643        return ret;
 644}
 645
 646static void isif_config_gain_offset(struct vpfe_isif_device *isif)
 647{
 648        struct vpfe_isif_gain_offsets_adj *gain_off_ptr =
 649                &isif->isif_cfg.bayer.config_params.gain_offset;
 650        void *__iomem base = isif->isif_cfg.base_addr;
 651        u32 val;
 652
 653        val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) |
 654              ((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) |
 655              ((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) |
 656              ((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) |
 657              ((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) |
 658              ((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT);
 659        isif_merge(base, GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
 660
 661        isif_write(base, isif->isif_cfg.isif_gain_params.cr_gain, CRGAIN);
 662        isif_write(base, isif->isif_cfg.isif_gain_params.cgr_gain, CGRGAIN);
 663        isif_write(base, isif->isif_cfg.isif_gain_params.cgb_gain, CGBGAIN);
 664        isif_write(base, isif->isif_cfg.isif_gain_params.cb_gain, CBGAIN);
 665        isif_write(base, isif->isif_cfg.isif_gain_params.offset & OFFSET_MASK,
 666                   COFSTA);
 667
 668}
 669
 670static void isif_config_bclamp(struct vpfe_isif_device *isif,
 671                   struct vpfe_isif_black_clamp *bc)
 672{
 673        u32 val;
 674
 675        /**
 676         * DC Offset is always added to image data irrespective of bc enable
 677         * status
 678         */
 679        val = bc->dc_offset & ISIF_BC_DCOFFSET_MASK;
 680        isif_write(isif->isif_cfg.base_addr, val, CLDCOFST);
 681
 682        if (!bc->en)
 683                return;
 684
 685        val = (bc->bc_mode_color & ISIF_BC_MODE_COLOR_MASK) <<
 686                ISIF_BC_MODE_COLOR_SHIFT;
 687
 688        /* Enable BC and horizontal clamp calculation paramaters */
 689        val = val | 1 | ((bc->horz.mode & ISIF_HORZ_BC_MODE_MASK) <<
 690              ISIF_HORZ_BC_MODE_SHIFT);
 691
 692        isif_write(isif->isif_cfg.base_addr, val, CLAMPCFG);
 693
 694        if (bc->horz.mode != VPFE_ISIF_HORZ_BC_DISABLE) {
 695                /*
 696                 * Window count for calculation
 697                 * Base window selection
 698                 * pixel limit
 699                 * Horizontal size of window
 700                 * vertical size of the window
 701                 * Horizontal start position of the window
 702                 * Vertical start position of the window
 703                 */
 704                val = (bc->horz.win_count_calc & ISIF_HORZ_BC_WIN_COUNT_MASK) |
 705                      ((bc->horz.base_win_sel_calc & 1) <<
 706                      ISIF_HORZ_BC_WIN_SEL_SHIFT) |
 707                      ((bc->horz.clamp_pix_limit & 1) <<
 708                      ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
 709                      ((bc->horz.win_h_sz_calc &
 710                      ISIF_HORZ_BC_WIN_H_SIZE_MASK) <<
 711                      ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
 712                      ((bc->horz.win_v_sz_calc &
 713                      ISIF_HORZ_BC_WIN_V_SIZE_MASK) <<
 714                      ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
 715
 716                isif_write(isif->isif_cfg.base_addr, val, CLHWIN0);
 717
 718                val = bc->horz.win_start_h_calc & ISIF_HORZ_BC_WIN_START_H_MASK;
 719                isif_write(isif->isif_cfg.base_addr, val, CLHWIN1);
 720
 721                val = bc->horz.win_start_v_calc & ISIF_HORZ_BC_WIN_START_V_MASK;
 722                isif_write(isif->isif_cfg.base_addr, val, CLHWIN2);
 723        }
 724
 725        /* vertical clamp calculation paramaters */
 726        /* OB H Valid */
 727        val = bc->vert.ob_h_sz_calc & ISIF_VERT_BC_OB_H_SZ_MASK;
 728
 729        /* Reset clamp value sel for previous line */
 730        val |= (bc->vert.reset_val_sel & ISIF_VERT_BC_RST_VAL_SEL_MASK) <<
 731                                ISIF_VERT_BC_RST_VAL_SEL_SHIFT;
 732
 733        /* Line average coefficient */
 734        val |= bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT;
 735        isif_write(isif->isif_cfg.base_addr, val, CLVWIN0);
 736
 737        /* Configured reset value */
 738        if (bc->vert.reset_val_sel == VPFE_ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL) {
 739                val = bc->vert.reset_clamp_val & ISIF_VERT_BC_RST_VAL_MASK;
 740                isif_write(isif->isif_cfg.base_addr, val, CLVRV);
 741        }
 742
 743        /* Optical Black horizontal start position */
 744        val = bc->vert.ob_start_h & ISIF_VERT_BC_OB_START_HORZ_MASK;
 745        isif_write(isif->isif_cfg.base_addr, val, CLVWIN1);
 746
 747        /* Optical Black vertical start position */
 748        val = bc->vert.ob_start_v & ISIF_VERT_BC_OB_START_VERT_MASK;
 749        isif_write(isif->isif_cfg.base_addr, val, CLVWIN2);
 750
 751        val = bc->vert.ob_v_sz_calc & ISIF_VERT_BC_OB_VERT_SZ_MASK;
 752        isif_write(isif->isif_cfg.base_addr, val, CLVWIN3);
 753
 754        /* Vertical start position for BC subtraction */
 755        val = bc->vert_start_sub & ISIF_BC_VERT_START_SUB_V_MASK;
 756        isif_write(isif->isif_cfg.base_addr, val, CLSV);
 757}
 758
 759/* This function will configure the window size to be capture in ISIF reg */
 760static void
 761isif_setwin(struct vpfe_isif_device *isif, struct v4l2_rect *image_win,
 762            enum isif_frmfmt frm_fmt, int ppc, int mode)
 763{
 764        int horz_nr_pixels;
 765        int vert_nr_lines;
 766        int horz_start;
 767        int vert_start;
 768        int mid_img;
 769
 770        /*
 771         * ppc - per pixel count. indicates how many pixels per cell
 772         * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
 773         * raw capture this is 1
 774         */
 775        horz_start = image_win->left << (ppc - 1);
 776        horz_nr_pixels = (image_win->width << (ppc - 1)) - 1;
 777
 778        /* Writing the horizontal info into the registers */
 779        isif_write(isif->isif_cfg.base_addr,
 780                   horz_start & START_PX_HOR_MASK, SPH);
 781        isif_write(isif->isif_cfg.base_addr,
 782                   horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
 783        vert_start = image_win->top;
 784
 785        if (frm_fmt == ISIF_FRMFMT_INTERLACED) {
 786                vert_nr_lines = (image_win->height >> 1) - 1;
 787                vert_start >>= 1;
 788                /* To account for VD since line 0 doesn't have any data */
 789                vert_start += 1;
 790        } else {
 791                /* To account for VD since line 0 doesn't have any data */
 792                vert_start += 1;
 793                vert_nr_lines = image_win->height - 1;
 794                /* configure VDINT0 and VDINT1 */
 795                mid_img = vert_start + (image_win->height / 2);
 796                isif_write(isif->isif_cfg.base_addr, mid_img, VDINT1);
 797        }
 798
 799        if (!mode)
 800                isif_write(isif->isif_cfg.base_addr, 0, VDINT0);
 801        else
 802                isif_write(isif->isif_cfg.base_addr, vert_nr_lines, VDINT0);
 803        isif_write(isif->isif_cfg.base_addr,
 804                   vert_start & START_VER_ONE_MASK, SLV0);
 805        isif_write(isif->isif_cfg.base_addr,
 806                   vert_start & START_VER_TWO_MASK, SLV1);
 807        isif_write(isif->isif_cfg.base_addr,
 808                   vert_nr_lines & NUM_LINES_VER, LNV);
 809}
 810
 811#define DM365_ISIF_DFCMWR_MEMORY_WRITE          1
 812#define DM365_ISIF_DFCMRD_MEMORY_READ           0x2
 813
 814static void
 815isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc)
 816{
 817#define DFC_WRITE_WAIT_COUNT    1000
 818        u32 count = DFC_WRITE_WAIT_COUNT;
 819        u32 val;
 820        int i;
 821
 822        if (!vdfc->en)
 823                return;
 824
 825        /* Correction mode */
 826        val = (vdfc->corr_mode & ISIF_VDFC_CORR_MOD_MASK) <<
 827               ISIF_VDFC_CORR_MOD_SHIFT;
 828
 829        /* Correct whole line or partial */
 830        if (vdfc->corr_whole_line)
 831                val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
 832
 833        /* level shift value */
 834        val |= (vdfc->def_level_shift & ISIF_VDFC_LEVEL_SHFT_MASK) <<
 835                ISIF_VDFC_LEVEL_SHFT_SHIFT;
 836
 837        isif_write(isif->isif_cfg.base_addr, val, DFCCTL);
 838
 839        /* Defect saturation level */
 840        val = vdfc->def_sat_level & ISIF_VDFC_SAT_LEVEL_MASK;
 841        isif_write(isif->isif_cfg.base_addr, val, VDFSATLV);
 842
 843        isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_vert &
 844                   ISIF_VDFC_POS_MASK, DFCMEM0);
 845        isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_horz &
 846                   ISIF_VDFC_POS_MASK, DFCMEM1);
 847        if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL ||
 848            vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
 849                isif_write(isif->isif_cfg.base_addr,
 850                           vdfc->table[0].level_at_pos, DFCMEM2);
 851                isif_write(isif->isif_cfg.base_addr,
 852                           vdfc->table[0].level_up_pixels, DFCMEM3);
 853                isif_write(isif->isif_cfg.base_addr,
 854                           vdfc->table[0].level_low_pixels, DFCMEM4);
 855        }
 856
 857        val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
 858        /* set DFCMARST and set DFCMWR */
 859        val |= 1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT;
 860        val |= 1;
 861        isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
 862
 863        while (count && (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x01))
 864                count--;
 865
 866        val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
 867        if (!count) {
 868                pr_debug("defect table write timeout !!\n");
 869                return;
 870        }
 871
 872        for (i = 1; i < vdfc->num_vdefects; i++) {
 873                isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_vert &
 874                        ISIF_VDFC_POS_MASK, DFCMEM0);
 875
 876                isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_horz &
 877                        ISIF_VDFC_POS_MASK, DFCMEM1);
 878
 879                if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL ||
 880                    vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
 881                        isif_write(isif->isif_cfg.base_addr,
 882                                   vdfc->table[i].level_at_pos, DFCMEM2);
 883                        isif_write(isif->isif_cfg.base_addr,
 884                                   vdfc->table[i].level_up_pixels, DFCMEM3);
 885                        isif_write(isif->isif_cfg.base_addr,
 886                                   vdfc->table[i].level_low_pixels, DFCMEM4);
 887                }
 888                val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
 889                /* clear DFCMARST and set DFCMWR */
 890                val &= ~(1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT);
 891                val |= 1;
 892                isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL);
 893
 894                count = DFC_WRITE_WAIT_COUNT;
 895                while (count && (isif_read(isif->isif_cfg.base_addr,
 896                        DFCMEMCTL) & 0x01))
 897                        count--;
 898
 899                val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
 900                if (!count) {
 901                        pr_debug("defect table write timeout !!\n");
 902                        return;
 903                }
 904        }
 905        if (vdfc->num_vdefects < VPFE_ISIF_VDFC_TABLE_SIZE) {
 906                /* Extra cycle needed */
 907                isif_write(isif->isif_cfg.base_addr, 0, DFCMEM0);
 908                isif_write(isif->isif_cfg.base_addr,
 909                           DM365_ISIF_MAX_DFCMEM1, DFCMEM1);
 910                isif_write(isif->isif_cfg.base_addr,
 911                           DM365_ISIF_DFCMWR_MEMORY_WRITE, DFCMEMCTL);
 912        }
 913        /* enable VDFC */
 914        isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT),
 915                   (1 << ISIF_VDFC_EN_SHIFT), DFCCTL);
 916
 917        isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT),
 918                   (0 << ISIF_VDFC_EN_SHIFT), DFCCTL);
 919
 920        isif_write(isif->isif_cfg.base_addr, 0x6, DFCMEMCTL);
 921        for (i = 0 ; i < vdfc->num_vdefects; i++) {
 922                count = DFC_WRITE_WAIT_COUNT;
 923                while (count &&
 924                        (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x2))
 925                        count--;
 926                val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL);
 927                if (!count) {
 928                        pr_debug("defect table write timeout !!\n");
 929                        return;
 930                }
 931                isif_write(isif->isif_cfg.base_addr,
 932                           DM365_ISIF_DFCMRD_MEMORY_READ, DFCMEMCTL);
 933        }
 934}
 935
 936static void
 937isif_config_csc(struct vpfe_isif_device *isif, struct vpfe_isif_df_csc *df_csc)
 938{
 939        u32 val1;
 940        u32 val2;
 941        u32 i;
 942
 943        if (!df_csc->csc.en) {
 944                isif_write(isif->isif_cfg.base_addr, 0, CSCCTL);
 945                return;
 946        }
 947        /* initialize all bits to 0 */
 948        val1 = 0;
 949        for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++) {
 950                if ((i % 2) == 0) {
 951                        /* CSCM - LSB */
 952                        val1 = ((df_csc->csc.coeff[i].integer &
 953                                ISIF_CSC_COEF_INTEG_MASK) <<
 954                                ISIF_CSC_COEF_INTEG_SHIFT) |
 955                                ((df_csc->csc.coeff[i].decimal &
 956                                ISIF_CSC_COEF_DECIMAL_MASK));
 957                } else {
 958
 959                        /* CSCM - MSB */
 960                        val2 = ((df_csc->csc.coeff[i].integer &
 961                                ISIF_CSC_COEF_INTEG_MASK) <<
 962                                ISIF_CSC_COEF_INTEG_SHIFT) |
 963                                ((df_csc->csc.coeff[i].decimal &
 964                                ISIF_CSC_COEF_DECIMAL_MASK));
 965                        val2 <<= ISIF_CSCM_MSB_SHIFT;
 966                        val2 |= val1;
 967                        isif_write(isif->isif_cfg.base_addr, val2,
 968                                   (CSCM0 + ((i-1) << 1)));
 969                }
 970        }
 971        /* program the active area */
 972        isif_write(isif->isif_cfg.base_addr, df_csc->start_pix &
 973                ISIF_DF_CSC_SPH_MASK, FMTSPH);
 974        /*
 975         * one extra pixel as required for CSC. Actually number of
 976         * pixel - 1 should be configured in this register. So we
 977         * need to subtract 1 before writing to FMTSPH, but we will
 978         * not do this since csc requires one extra pixel
 979         */
 980        isif_write(isif->isif_cfg.base_addr, df_csc->num_pixels &
 981                ISIF_DF_CSC_SPH_MASK, FMTLNH);
 982        isif_write(isif->isif_cfg.base_addr, df_csc->start_line &
 983                ISIF_DF_CSC_SPH_MASK, FMTSLV);
 984        /*
 985         * one extra line as required for CSC. See reason documented for
 986         * num_pixels
 987         */
 988        isif_write(isif->isif_cfg.base_addr, df_csc->num_lines &
 989                ISIF_DF_CSC_SPH_MASK, FMTLNV);
 990        /* Enable CSC */
 991        isif_write(isif->isif_cfg.base_addr, 1, CSCCTL);
 992}
 993
 994static void
 995isif_config_linearization(struct vpfe_isif_device *isif,
 996                          struct vpfe_isif_linearize *linearize)
 997{
 998        u32 val;
 999        u32 i;
1000
1001        if (!linearize->en) {
1002                isif_write(isif->isif_cfg.base_addr, 0, LINCFG0);
1003                return;
1004        }
1005        /* shift value for correction */
1006        val = (linearize->corr_shft & ISIF_LIN_CORRSFT_MASK) <<
1007              ISIF_LIN_CORRSFT_SHIFT;
1008        /* enable */
1009        val |= 1;
1010        isif_write(isif->isif_cfg.base_addr, val, LINCFG0);
1011        /* Scale factor */
1012        val = (linearize->scale_fact.integer & 1) <<
1013              ISIF_LIN_SCALE_FACT_INTEG_SHIFT;
1014        val |= linearize->scale_fact.decimal & ISIF_LIN_SCALE_FACT_DECIMAL_MASK;
1015        isif_write(isif->isif_cfg.base_addr, val, LINCFG1);
1016
1017        for (i = 0; i < VPFE_ISIF_LINEAR_TAB_SIZE; i++) {
1018                val = linearize->table[i] & ISIF_LIN_ENTRY_MASK;
1019                if (i%2)
1020                        isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 1);
1021                else
1022                        isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 0);
1023        }
1024}
1025
1026static void
1027isif_config_culling(struct vpfe_isif_device *isif, struct vpfe_isif_cul *cul)
1028{
1029        u32 val;
1030
1031        /* Horizontal pattern */
1032        val = cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT;
1033        val |= cul->hcpat_odd;
1034        isif_write(isif->isif_cfg.base_addr, val, CULH);
1035        /* vertical pattern */
1036        isif_write(isif->isif_cfg.base_addr, cul->vcpat, CULV);
1037        /* LPF */
1038        isif_merge(isif->isif_cfg.base_addr, ISIF_LPF_MASK << ISIF_LPF_SHIFT,
1039                   cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
1040}
1041
1042static int isif_get_pix_fmt(u32 mbus_code)
1043{
1044        switch (mbus_code) {
1045        case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
1046        case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
1047        case V4L2_MBUS_FMT_SGRBG12_1X12:
1048                return ISIF_PIXFMT_RAW;
1049
1050        case V4L2_MBUS_FMT_YUYV8_2X8:
1051        case V4L2_MBUS_FMT_UYVY8_2X8:
1052        case V4L2_MBUS_FMT_YUYV10_2X10:
1053        case V4L2_MBUS_FMT_Y8_1X8:
1054                return ISIF_PIXFMT_YCBCR_8BIT;
1055
1056        case V4L2_MBUS_FMT_YUYV8_1X16:
1057        case V4L2_MBUS_FMT_YUYV10_1X20:
1058                return ISIF_PIXFMT_YCBCR_16BIT;
1059
1060        default:
1061                break;
1062        }
1063        return -EINVAL;
1064}
1065
1066#define ISIF_INTERLACE_INVERSE_MODE             0x4b6d
1067#define ISIF_INTERLACE_NON_INVERSE_MODE         0x0b6d
1068#define ISIF_PROGRESSIVE_INVERSE_MODE           0x4000
1069#define ISIF_PROGRESSIVE_NON_INVERSE_MODE       0x0000
1070
1071static int isif_config_raw(struct v4l2_subdev *sd, int mode)
1072{
1073        struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1074        struct isif_params_raw *params = &isif->isif_cfg.bayer;
1075        struct vpfe_isif_raw_config *module_params =
1076                                &isif->isif_cfg.bayer.config_params;
1077        struct v4l2_mbus_framefmt *format;
1078        int pix_fmt;
1079        u32 val;
1080
1081        format = &isif->formats[ISIF_PAD_SINK];
1082
1083        /* In case of user has set BT656IF earlier, it should be reset
1084         * when configuring for raw input.
1085         */
1086        isif_write(isif->isif_cfg.base_addr, 0, REC656IF);
1087        /* Configure CCDCFG register
1088         * Set CCD Not to swap input since input is RAW data
1089         * Set FID detection function to Latch at V-Sync
1090         * Set WENLOG - isif valid area
1091         * Set TRGSEL
1092         * Set EXTRG
1093         * Packed to 8 or 16 bits
1094         */
1095        val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
1096              ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
1097              ISIF_CCDCFG_EXTRG_DISABLE | (isif->isif_cfg.data_pack &
1098              ISIF_DATA_PACK_MASK);
1099        isif_write(isif->isif_cfg.base_addr, val, CCDCFG);
1100
1101        pix_fmt = isif_get_pix_fmt(format->code);
1102        if (pix_fmt < 0) {
1103                pr_debug("Invalid pix_fmt(input mode)\n");
1104                return -EINVAL;
1105        }
1106        /*
1107         * Configure the vertical sync polarity(MODESET.VDPOL)
1108         * Configure the horizontal sync polarity (MODESET.HDPOL)
1109         * Configure frame id polarity (MODESET.FLDPOL)
1110         * Configure data polarity
1111         * Configure External WEN Selection
1112         * Configure frame format(progressive or interlace)
1113         * Configure pixel format (Input mode)
1114         * Configure the data shift
1115         */
1116        val = ISIF_VDHDOUT_INPUT | ((params->vd_pol & ISIF_VD_POL_MASK) <<
1117              ISIF_VD_POL_SHIFT) | ((params->hd_pol & ISIF_HD_POL_MASK) <<
1118              ISIF_HD_POL_SHIFT) | ((params->fid_pol & ISIF_FID_POL_MASK) <<
1119              ISIF_FID_POL_SHIFT) | ((ISIF_DATAPOL_NORMAL &
1120              ISIF_DATAPOL_MASK) << ISIF_DATAPOL_SHIFT) | ((ISIF_EXWEN_DISABLE &
1121              ISIF_EXWEN_MASK) << ISIF_EXWEN_SHIFT) | ((params->frm_fmt &
1122              ISIF_FRM_FMT_MASK) << ISIF_FRM_FMT_SHIFT) | ((pix_fmt &
1123              ISIF_INPUT_MASK) << ISIF_INPUT_SHIFT);
1124
1125        /* currently only V4L2_MBUS_FMT_SGRBG12_1X12 is
1126         * supported. shift appropriately depending on
1127         * different MBUS fmt's added
1128         */
1129        if (format->code == V4L2_MBUS_FMT_SGRBG12_1X12)
1130                val |= ((VPFE_ISIF_NO_SHIFT &
1131                        ISIF_DATASFT_MASK) << ISIF_DATASFT_SHIFT);
1132
1133        isif_write(isif->isif_cfg.base_addr, val, MODESET);
1134        /*
1135         * Configure GAMMAWD register
1136         * CFA pattern setting
1137         */
1138        val = (params->cfa_pat & ISIF_GAMMAWD_CFA_MASK) <<
1139                ISIF_GAMMAWD_CFA_SHIFT;
1140        /* Gamma msb */
1141        if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10ALAW8)
1142                val = val | ISIF_ALAW_ENABLE;
1143
1144        val = val | ((params->data_msb & ISIF_ALAW_GAMA_WD_MASK) <<
1145                        ISIF_ALAW_GAMA_WD_SHIFT);
1146
1147        isif_write(isif->isif_cfg.base_addr, val, CGAMMAWD);
1148        /* Configure DPCM compression settings */
1149        if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) {
1150                val =  1 << ISIF_DPCM_EN_SHIFT;
1151                val |= (params->dpcm_predictor &
1152                        ISIF_DPCM_PREDICTOR_MASK) << ISIF_DPCM_PREDICTOR_SHIFT;
1153        }
1154        isif_write(isif->isif_cfg.base_addr, val, MISC);
1155        /* Configure Gain & Offset */
1156        isif_config_gain_offset(isif);
1157        /* Configure Color pattern */
1158        if (format->code == V4L2_MBUS_FMT_SGRBG12_1X12)
1159                val = isif_sgrbg_pattern;
1160        else
1161                /* default set to rggb */
1162                val = isif_srggb_pattern;
1163
1164        isif_write(isif->isif_cfg.base_addr, val, CCOLP);
1165
1166        /* Configure HSIZE register  */
1167        val = (params->horz_flip_en & ISIF_HSIZE_FLIP_MASK) <<
1168              ISIF_HSIZE_FLIP_SHIFT;
1169
1170        /* calculate line offset in 32 bytes based on pack value */
1171        if (isif->isif_cfg.data_pack == ISIF_PACK_8BIT)
1172                val |= ((params->win.width + 31) >> 5) & ISIF_LINEOFST_MASK;
1173        else if (isif->isif_cfg.data_pack == ISIF_PACK_12BIT)
1174                val |= ((((params->win.width + (params->win.width >> 2)) +
1175                        31) >> 5) & ISIF_LINEOFST_MASK);
1176        else
1177                val |= (((params->win.width * 2) + 31) >> 5) &
1178                        ISIF_LINEOFST_MASK;
1179        isif_write(isif->isif_cfg.base_addr, val, HSIZE);
1180        /* Configure SDOFST register  */
1181        if (params->frm_fmt == ISIF_FRMFMT_INTERLACED) {
1182                if (params->image_invert_en)
1183                        /* For interlace inverse mode */
1184                        isif_write(isif->isif_cfg.base_addr,
1185                                   ISIF_INTERLACE_INVERSE_MODE, SDOFST);
1186                else
1187                        /* For interlace non inverse mode */
1188                        isif_write(isif->isif_cfg.base_addr,
1189                                   ISIF_INTERLACE_NON_INVERSE_MODE, SDOFST);
1190        } else if (params->frm_fmt == ISIF_FRMFMT_PROGRESSIVE) {
1191                if (params->image_invert_en)
1192                        isif_write(isif->isif_cfg.base_addr,
1193                                   ISIF_PROGRESSIVE_INVERSE_MODE, SDOFST);
1194                else
1195                        /* For progessive non inverse mode */
1196                        isif_write(isif->isif_cfg.base_addr,
1197                                   ISIF_PROGRESSIVE_NON_INVERSE_MODE, SDOFST);
1198        }
1199        /* Configure video window */
1200        isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
1201        /* Configure Black Clamp */
1202        isif_config_bclamp(isif, &module_params->bclamp);
1203        /* Configure Vertical Defection Pixel Correction */
1204        isif_config_dfc(isif, &module_params->dfc);
1205        if (!module_params->df_csc.df_or_csc)
1206                /* Configure Color Space Conversion */
1207                isif_config_csc(isif, &module_params->df_csc);
1208
1209        isif_config_linearization(isif, &module_params->linearize);
1210        /* Configure Culling */
1211        isif_config_culling(isif, &module_params->culling);
1212        /* Configure Horizontal and vertical offsets(DFC,LSC,Gain) */
1213        val = module_params->horz_offset & ISIF_DATA_H_OFFSET_MASK;
1214        isif_write(isif->isif_cfg.base_addr, val, DATAHOFST);
1215
1216        val = module_params->vert_offset & ISIF_DATA_V_OFFSET_MASK;
1217        isif_write(isif->isif_cfg.base_addr, val, DATAVOFST);
1218
1219        return 0;
1220}
1221
1222#define DM365_ISIF_HSIZE_MASK           0xffffffe0
1223#define DM365_ISIF_SDOFST_2_LINES       0x00000249
1224
1225/* This function will configure ISIF for YCbCr parameters. */
1226static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
1227{
1228        struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1229        struct isif_ycbcr_config *params = &isif->isif_cfg.ycbcr;
1230        struct v4l2_mbus_framefmt *format;
1231        int pix_fmt;
1232        u32 modeset;
1233        u32 ccdcfg;
1234
1235        format = &isif->formats[ISIF_PAD_SINK];
1236        /*
1237         * first reset the ISIF
1238         * all registers have default values after reset
1239         * This is important since we assume default values to be set in
1240         * a lot of registers that we didn't touch
1241         */
1242        /* start with all bits zero */
1243        ccdcfg = modeset = 0;
1244        pix_fmt = isif_get_pix_fmt(format->code);
1245        if (pix_fmt < 0) {
1246                pr_debug("Invalid pix_fmt(input mode)\n");
1247                return -EINVAL;
1248        }
1249        /* configure pixel format or input mode */
1250        modeset = modeset | ((pix_fmt & ISIF_INPUT_MASK) <<
1251                  ISIF_INPUT_SHIFT) | ((params->frm_fmt & ISIF_FRM_FMT_MASK) <<
1252                  ISIF_FRM_FMT_SHIFT) | (((params->fid_pol &
1253                  ISIF_FID_POL_MASK) << ISIF_FID_POL_SHIFT)) |
1254                  (((params->hd_pol & ISIF_HD_POL_MASK) << ISIF_HD_POL_SHIFT)) |
1255                  (((params->vd_pol & ISIF_VD_POL_MASK) << ISIF_VD_POL_SHIFT));
1256        /* pack the data to 8-bit CCDCCFG */
1257        switch (format->code) {
1258        case V4L2_MBUS_FMT_YUYV8_2X8:
1259        case V4L2_MBUS_FMT_UYVY8_2X8:
1260                if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1261                        pr_debug("Invalid pix_fmt(input mode)\n");
1262                        return -EINVAL;
1263                }
1264                modeset |= ((VPFE_PINPOL_NEGATIVE & ISIF_VD_POL_MASK) <<
1265                                ISIF_VD_POL_SHIFT);
1266                isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1267                ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR;
1268                break;
1269
1270        case V4L2_MBUS_FMT_YUYV10_2X10:
1271                if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1272                        pr_debug("Invalid pix_fmt(input mode)\n");
1273                        return -EINVAL;
1274                }
1275                /* setup BT.656, embedded sync  */
1276                isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1277                /* enable 10 bit mode in ccdcfg */
1278                ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR |
1279                        ISIF_BW656_ENABLE;
1280                break;
1281
1282        case V4L2_MBUS_FMT_YUYV10_1X20:
1283                if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
1284                        pr_debug("Invalid pix_fmt(input mode)\n");
1285                        return -EINVAL;
1286                }
1287                isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
1288                break;
1289
1290        case V4L2_MBUS_FMT_Y8_1X8:
1291                ccdcfg |= ISIF_PACK_8BIT;
1292                ccdcfg |= ISIF_YCINSWP_YCBCR;
1293                if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
1294                        pr_debug("Invalid pix_fmt(input mode)\n");
1295                        return -EINVAL;
1296                }
1297                break;
1298
1299        case V4L2_MBUS_FMT_YUYV8_1X16:
1300                if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
1301                        pr_debug("Invalid pix_fmt(input mode)\n");
1302                        return -EINVAL;
1303                }
1304                break;
1305
1306        default:
1307                /* should never come here */
1308                pr_debug("Invalid interface type\n");
1309                return -EINVAL;
1310        }
1311        isif_write(isif->isif_cfg.base_addr, modeset, MODESET);
1312        /* Set up pix order */
1313        ccdcfg |= (params->pix_order & ISIF_PIX_ORDER_MASK) <<
1314                ISIF_PIX_ORDER_SHIFT;
1315        isif_write(isif->isif_cfg.base_addr, ccdcfg, CCDCFG);
1316        /* configure video window */
1317        if (format->code == V4L2_MBUS_FMT_YUYV10_1X20 ||
1318                        format->code == V4L2_MBUS_FMT_YUYV8_1X16)
1319                isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
1320        else
1321                isif_setwin(isif, &params->win, params->frm_fmt, 2, mode);
1322
1323        /*
1324         * configure the horizontal line offset
1325         * this is done by rounding up width to a multiple of 16 pixels
1326         * and multiply by two to account for y:cb:cr 4:2:2 data
1327         */
1328        isif_write(isif->isif_cfg.base_addr,
1329                   ((((params->win.width * 2) + 31) &
1330                   DM365_ISIF_HSIZE_MASK) >> 5), HSIZE);
1331
1332        /* configure the memory line offset */
1333        if (params->frm_fmt == ISIF_FRMFMT_INTERLACED &&
1334            params->buf_type == ISIF_BUFTYPE_FLD_INTERLEAVED)
1335                /* two fields are interleaved in memory */
1336                isif_write(isif->isif_cfg.base_addr,
1337                           DM365_ISIF_SDOFST_2_LINES, SDOFST);
1338        return 0;
1339}
1340
1341static int isif_configure(struct v4l2_subdev *sd, int mode)
1342{
1343        struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1344        struct v4l2_mbus_framefmt *format;
1345
1346        format = &isif->formats[ISIF_PAD_SINK];
1347
1348        switch (format->code) {
1349        case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
1350        case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
1351        case V4L2_MBUS_FMT_SGRBG12_1X12:
1352                return isif_config_raw(sd, mode);
1353
1354        case V4L2_MBUS_FMT_YUYV8_2X8:
1355        case V4L2_MBUS_FMT_UYVY8_2X8:
1356        case V4L2_MBUS_FMT_YUYV10_2X10:
1357        case V4L2_MBUS_FMT_Y8_1X8:
1358        case V4L2_MBUS_FMT_YUYV8_1X16:
1359        case V4L2_MBUS_FMT_YUYV10_1X20:
1360                return isif_config_ycbcr(sd, mode);
1361
1362        default:
1363                break;
1364        }
1365        return -EINVAL;
1366}
1367
1368/*
1369 * isif_set_stream() - Enable/Disable streaming on the ISIF module
1370 * @sd: VPFE ISIF V4L2 subdevice
1371 * @enable: Enable/disable stream
1372 */
1373static int isif_set_stream(struct v4l2_subdev *sd, int enable)
1374{
1375        struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1376        int ret;
1377
1378        if (enable) {
1379                ret = isif_configure(sd,
1380                        (isif->output == ISIF_OUTPUT_MEMORY) ? 0 : 1);
1381                if (ret)
1382                        return ret;
1383                if (isif->output == ISIF_OUTPUT_MEMORY)
1384                        isif_enable_output_to_sdram(isif, 1);
1385                isif_enable(isif, 1);
1386        } else {
1387                isif_enable(isif, 0);
1388                isif_enable_output_to_sdram(isif, 0);
1389        }
1390
1391        return 0;
1392}
1393
1394/*
1395 * __isif_get_format() - helper function for getting isif format
1396 * @isif: pointer to isif private structure.
1397 * @pad: pad number.
1398 * @fh: V4L2 subdev file handle.
1399 * @which: wanted subdev format.
1400 */
1401static struct v4l2_mbus_framefmt *
1402__isif_get_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh,
1403                  unsigned int pad, enum v4l2_subdev_format_whence which)
1404{
1405        if (which == V4L2_SUBDEV_FORMAT_TRY) {
1406                struct v4l2_subdev_format fmt;
1407
1408                fmt.pad = pad;
1409                fmt.which = which;
1410
1411                return v4l2_subdev_get_try_format(fh, pad);
1412        }
1413        return &isif->formats[pad];
1414}
1415
1416/*
1417* isif_set_format() - set format on pad
1418* @sd    : VPFE ISIF device
1419* @fh    : V4L2 subdev file handle
1420* @fmt   : pointer to v4l2 subdev format structure
1421*
1422* Return 0 on success or -EINVAL if format or pad is invalid
1423*/
1424static int
1425isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1426                struct v4l2_subdev_format *fmt)
1427{
1428        struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1429        struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
1430        struct v4l2_mbus_framefmt *format;
1431
1432        format = __isif_get_format(isif, fh, fmt->pad, fmt->which);
1433        if (format == NULL)
1434                return -EINVAL;
1435
1436        isif_try_format(isif, fh, fmt);
1437        memcpy(format, &fmt->format, sizeof(*format));
1438
1439        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
1440                return 0;
1441
1442        if (fmt->pad == ISIF_PAD_SOURCE)
1443                return isif_config_format(vpfe_dev, fmt->pad);
1444
1445        return 0;
1446}
1447
1448/*
1449 * isif_get_format() - Retrieve the video format on a pad
1450 * @sd: VPFE ISIF V4L2 subdevice
1451 * @fh: V4L2 subdev file handle
1452 * @fmt: pointer to v4l2 subdev format structure
1453 *
1454 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
1455 * to the format type.
1456 */
1457static int
1458isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1459                struct v4l2_subdev_format *fmt)
1460{
1461        struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1462        struct v4l2_mbus_framefmt *format;
1463
1464        format = __isif_get_format(vpfe_isif, fh, fmt->pad, fmt->which);
1465        if (format == NULL)
1466                return -EINVAL;
1467
1468        memcpy(&fmt->format, format, sizeof(fmt->format));
1469
1470        return 0;
1471}
1472
1473/*
1474 * isif_enum_frame_size() - enum frame sizes on pads
1475 * @sd: VPFE isif V4L2 subdevice
1476 * @fh: V4L2 subdev file handle
1477 * @code: pointer to v4l2_subdev_frame_size_enum structure
1478 */
1479static int
1480isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1481                     struct v4l2_subdev_frame_size_enum *fse)
1482{
1483        struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1484        struct v4l2_subdev_format format;
1485
1486        if (fse->index != 0)
1487                return -EINVAL;
1488
1489        format.pad = fse->pad;
1490        format.format.code = fse->code;
1491        format.format.width = 1;
1492        format.format.height = 1;
1493        format.which = V4L2_SUBDEV_FORMAT_TRY;
1494        isif_try_format(isif, fh, &format);
1495        fse->min_width = format.format.width;
1496        fse->min_height = format.format.height;
1497
1498        if (format.format.code != fse->code)
1499                return -EINVAL;
1500
1501        format.pad = fse->pad;
1502        format.format.code = fse->code;
1503        format.format.width = -1;
1504        format.format.height = -1;
1505        format.which = V4L2_SUBDEV_FORMAT_TRY;
1506        isif_try_format(isif, fh, &format);
1507        fse->max_width = format.format.width;
1508        fse->max_height = format.format.height;
1509
1510        return 0;
1511}
1512
1513/*
1514 * isif_enum_mbus_code() - enum mbus codes for pads
1515 * @sd: VPFE isif V4L2 subdevice
1516 * @fh: V4L2 subdev file handle
1517 * @code: pointer to v4l2_subdev_mbus_code_enum structure
1518 */
1519static int
1520isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1521                    struct v4l2_subdev_mbus_code_enum *code)
1522{
1523        switch (code->pad) {
1524        case ISIF_PAD_SINK:
1525        case ISIF_PAD_SOURCE:
1526                if (code->index >= ARRAY_SIZE(isif_fmts))
1527                        return -EINVAL;
1528                code->code = isif_fmts[code->index];
1529                break;
1530
1531        default:
1532                return -EINVAL;
1533        }
1534
1535        return 0;
1536}
1537
1538/*
1539 * isif_pad_set_crop() - set crop rectangle on pad
1540 * @sd: VPFE isif V4L2 subdevice
1541 * @fh: V4L2 subdev file handle
1542 * @code: pointer to v4l2_subdev_mbus_code_enum structure
1543 *
1544 * Return 0 on success, -EINVAL if pad is invalid
1545 */
1546static int
1547isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1548                  struct v4l2_subdev_crop *crop)
1549{
1550        struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1551        struct v4l2_mbus_framefmt *format;
1552
1553        /* check wether its a valid pad */
1554        if (crop->pad != ISIF_PAD_SINK)
1555                return -EINVAL;
1556
1557        format = __isif_get_format(vpfe_isif, fh, crop->pad, crop->which);
1558        if (format == NULL)
1559                return -EINVAL;
1560
1561        /* check wether crop rect is within limits */
1562        if (crop->rect.top < 0 || crop->rect.left < 0 ||
1563                (crop->rect.left + crop->rect.width >
1564                vpfe_isif->formats[ISIF_PAD_SINK].width) ||
1565                (crop->rect.top + crop->rect.height >
1566                        vpfe_isif->formats[ISIF_PAD_SINK].height)) {
1567                crop->rect.left = 0;
1568                crop->rect.top = 0;
1569                crop->rect.width = format->width;
1570                crop->rect.height = format->height;
1571        }
1572        /* adjust the width to 16 pixel boundary */
1573        crop->rect.width = ((crop->rect.width + 15) & ~0xf);
1574        vpfe_isif->crop = crop->rect;
1575        if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1576                isif_set_image_window(vpfe_isif);
1577        } else {
1578                struct v4l2_rect *rect;
1579
1580                rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK);
1581                memcpy(rect, &vpfe_isif->crop, sizeof(*rect));
1582        }
1583        return 0;
1584}
1585
1586/*
1587 * isif_pad_get_crop() - get crop rectangle on pad
1588 * @sd: VPFE isif V4L2 subdevice
1589 * @fh: V4L2 subdev file handle
1590 * @code: pointer to v4l2_subdev_mbus_code_enum structure
1591 *
1592 * Return 0 on success, -EINVAL if pad is invalid
1593 */
1594static int
1595isif_pad_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1596                  struct v4l2_subdev_crop *crop)
1597{
1598        struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
1599
1600        /* check wether its a valid pad */
1601        if (crop->pad != ISIF_PAD_SINK)
1602                return -EINVAL;
1603
1604        if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
1605                struct v4l2_rect *rect;
1606                rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK);
1607                memcpy(&crop->rect, rect, sizeof(*rect));
1608        } else {
1609                crop->rect = vpfe_isif->crop;
1610        }
1611
1612        return 0;
1613}
1614
1615/*
1616 * isif_init_formats() - Initialize formats on all pads
1617 * @sd: VPFE isif V4L2 subdevice
1618 * @fh: V4L2 subdev file handle
1619 *
1620 * Initialize all pad formats with default values. If fh is not NULL, try
1621 * formats are initialized on the file handle. Otherwise active formats are
1622 * initialized on the device.
1623 */
1624static int
1625isif_init_formats(struct v4l2_subdev *sd,
1626                  struct v4l2_subdev_fh *fh)
1627{
1628        struct v4l2_subdev_format format;
1629        struct v4l2_subdev_crop crop;
1630
1631        memset(&format, 0, sizeof(format));
1632        format.pad = ISIF_PAD_SINK;
1633        format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1634        format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
1635        format.format.width = MAX_WIDTH;
1636        format.format.height = MAX_HEIGHT;
1637        isif_set_format(sd, fh, &format);
1638
1639        memset(&format, 0, sizeof(format));
1640        format.pad = ISIF_PAD_SOURCE;
1641        format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1642        format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
1643        format.format.width = MAX_WIDTH;
1644        format.format.height = MAX_HEIGHT;
1645        isif_set_format(sd, fh, &format);
1646
1647        memset(&crop, 0, sizeof(crop));
1648        crop.pad = ISIF_PAD_SINK;
1649        crop.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1650        crop.rect.width = MAX_WIDTH;
1651        crop.rect.height = MAX_HEIGHT;
1652        isif_pad_set_crop(sd, fh, &crop);
1653
1654        return 0;
1655}
1656
1657/* subdev core operations */
1658static const struct v4l2_subdev_core_ops isif_v4l2_core_ops = {
1659        .ioctl = isif_ioctl,
1660};
1661
1662/* subdev file operations */
1663static const struct v4l2_subdev_internal_ops isif_v4l2_internal_ops = {
1664        .open = isif_init_formats,
1665};
1666
1667/* subdev video operations */
1668static const struct v4l2_subdev_video_ops isif_v4l2_video_ops = {
1669        .s_stream = isif_set_stream,
1670};
1671
1672/* subdev pad operations */
1673static const struct v4l2_subdev_pad_ops isif_v4l2_pad_ops = {
1674        .enum_mbus_code = isif_enum_mbus_code,
1675        .enum_frame_size = isif_enum_frame_size,
1676        .get_fmt = isif_get_format,
1677        .set_fmt = isif_set_format,
1678        .set_crop = isif_pad_set_crop,
1679        .get_crop = isif_pad_get_crop,
1680};
1681
1682/* subdev operations */
1683static const struct v4l2_subdev_ops isif_v4l2_ops = {
1684        .core = &isif_v4l2_core_ops,
1685        .video = &isif_v4l2_video_ops,
1686        .pad = &isif_v4l2_pad_ops,
1687};
1688
1689/*
1690 * Media entity operations
1691 */
1692
1693/*
1694 * isif_link_setup() - Setup isif connections
1695 * @entity: isif media entity
1696 * @local: Pad at the local end of the link
1697 * @remote: Pad at the remote end of the link
1698 * @flags: Link flags
1699 *
1700 * return -EINVAL or zero on success
1701 */
1702static int
1703isif_link_setup(struct media_entity *entity, const struct media_pad *local,
1704                const struct media_pad *remote, u32 flags)
1705{
1706        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1707        struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
1708
1709        switch (local->index | media_entity_type(remote->entity)) {
1710        case ISIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1711                /* read from decoder/sensor */
1712                if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1713                        isif->input = ISIF_INPUT_NONE;
1714                        break;
1715                }
1716                if (isif->input != ISIF_INPUT_NONE)
1717                        return -EBUSY;
1718                isif->input = ISIF_INPUT_PARALLEL;
1719                break;
1720
1721        case ISIF_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1722                /* write to memory */
1723                if (flags & MEDIA_LNK_FL_ENABLED)
1724                        isif->output = ISIF_OUTPUT_MEMORY;
1725                else
1726                        isif->output = ISIF_OUTPUT_NONE;
1727                break;
1728
1729        case ISIF_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
1730                if (flags & MEDIA_LNK_FL_ENABLED)
1731                        isif->output = ISIF_OUTPUT_IPIPEIF;
1732                else
1733                        isif->output = ISIF_OUTPUT_NONE;
1734                break;
1735
1736        default:
1737                return -EINVAL;
1738        }
1739
1740        return 0;
1741}
1742static const struct media_entity_operations isif_media_ops = {
1743        .link_setup = isif_link_setup,
1744};
1745
1746/*
1747 * vpfe_isif_unregister_entities() - isif unregister entity
1748 * @isif - pointer to isif subdevice structure.
1749 */
1750void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif)
1751{
1752        vpfe_video_unregister(&isif->video_out);
1753        /* cleanup entity */
1754        media_entity_cleanup(&isif->subdev.entity);
1755        /* unregister subdev */
1756        v4l2_device_unregister_subdev(&isif->subdev);
1757}
1758
1759static void isif_restore_defaults(struct vpfe_isif_device *isif)
1760{
1761        enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
1762        int i;
1763
1764        memset(&isif->isif_cfg.bayer.config_params, 0,
1765               sizeof(struct vpfe_isif_raw_config));
1766
1767        isif->isif_cfg.bayer.config_params.linearize.corr_shft =
1768                                        VPFE_ISIF_NO_SHIFT;
1769        isif->isif_cfg.bayer.config_params.linearize.scale_fact.integer = 1;
1770        isif->isif_cfg.bayer.config_params.culling.hcpat_odd =
1771                        ISIF_CULLING_HCAPT_ODD;
1772        isif->isif_cfg.bayer.config_params.culling.hcpat_even =
1773                        ISIF_CULLING_HCAPT_EVEN;
1774        isif->isif_cfg.bayer.config_params.culling.vcpat = ISIF_CULLING_VCAPT;
1775        /* Enable clock to ISIF, IPIPEIF and BL */
1776        vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
1777        vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
1778        vpss_enable_clock(VPSS_BL_CLOCK, 1);
1779
1780        /* set all registers to default value */
1781        for (i = 0; i <= 0x1f8; i += 4)
1782                isif_write(isif->isif_cfg.base_addr, 0, i);
1783        /* no culling support */
1784        isif_write(isif->isif_cfg.base_addr, 0xffff, CULH);
1785        isif_write(isif->isif_cfg.base_addr, 0xff, CULV);
1786
1787        /* Set default offset and gain */
1788        isif_config_gain_offset(isif);
1789        vpss_select_ccdc_source(source);
1790}
1791
1792/*
1793 * vpfe_isif_register_entities() - isif register entity
1794 * @isif - pointer to isif subdevice structure.
1795 * @vdev: pointer to v4l2 device structure.
1796 */
1797int vpfe_isif_register_entities(struct vpfe_isif_device *isif,
1798                            struct v4l2_device *vdev)
1799{
1800        struct vpfe_device *vpfe_dev = to_vpfe_device(isif);
1801        unsigned int flags;
1802        int ret;
1803
1804        /* Register the subdev */
1805        ret = v4l2_device_register_subdev(vdev, &isif->subdev);
1806        if (ret < 0)
1807                return ret;
1808
1809        isif_restore_defaults(isif);
1810        ret = vpfe_video_register(&isif->video_out, vdev);
1811        if (ret) {
1812                pr_err("Failed to register isif video out device\n");
1813                goto out_video_register;
1814        }
1815        isif->video_out.vpfe_dev = vpfe_dev;
1816        flags = 0;
1817        /* connect isif to video node */
1818        ret = media_entity_create_link(&isif->subdev.entity, 1,
1819                                       &isif->video_out.video_dev.entity,
1820                                       0, flags);
1821        if (ret < 0)
1822                goto out_create_link;
1823        return 0;
1824out_create_link:
1825        vpfe_video_unregister(&isif->video_out);
1826out_video_register:
1827        v4l2_device_unregister_subdev(&isif->subdev);
1828        return ret;
1829}
1830
1831/* -------------------------------------------------------------------
1832 * V4L2 subdev control operations
1833 */
1834
1835static int vpfe_isif_s_ctrl(struct v4l2_ctrl *ctrl)
1836{
1837        struct vpfe_isif_device *isif =
1838             container_of(ctrl->handler, struct vpfe_isif_device, ctrls);
1839        struct isif_oper_config *config = &isif->isif_cfg;
1840
1841        switch (ctrl->id) {
1842        case VPFE_CID_DPCM_PREDICTOR:
1843                config->bayer.dpcm_predictor = ctrl->val;
1844                break;
1845
1846        case VPFE_ISIF_CID_CRGAIN:
1847                config->isif_gain_params.cr_gain = ctrl->val;
1848                break;
1849
1850        case VPFE_ISIF_CID_CGRGAIN:
1851                config->isif_gain_params.cgr_gain = ctrl->val;
1852                break;
1853
1854        case VPFE_ISIF_CID_CGBGAIN:
1855                config->isif_gain_params.cgb_gain = ctrl->val;
1856                break;
1857
1858        case VPFE_ISIF_CID_CBGAIN:
1859                config->isif_gain_params.cb_gain = ctrl->val;
1860                break;
1861
1862        case VPFE_ISIF_CID_GAIN_OFFSET:
1863                config->isif_gain_params.offset = ctrl->val;
1864                break;
1865
1866        default:
1867                return -EINVAL;
1868        }
1869        return 0;
1870}
1871
1872static const struct v4l2_ctrl_ops vpfe_isif_ctrl_ops = {
1873        .s_ctrl = vpfe_isif_s_ctrl,
1874};
1875
1876static const struct v4l2_ctrl_config vpfe_isif_dpcm_pred = {
1877        .ops = &vpfe_isif_ctrl_ops,
1878        .id = VPFE_CID_DPCM_PREDICTOR,
1879        .name = "DPCM Predictor",
1880        .type = V4L2_CTRL_TYPE_INTEGER,
1881        .min = 0,
1882        .max = 1,
1883        .step = 1,
1884        .def = 0,
1885};
1886
1887static const struct v4l2_ctrl_config vpfe_isif_crgain = {
1888        .ops = &vpfe_isif_ctrl_ops,
1889        .id = VPFE_ISIF_CID_CRGAIN,
1890        .name = "CRGAIN",
1891        .type = V4L2_CTRL_TYPE_INTEGER,
1892        .min = 0,
1893        .max = (1 << 12) - 1,
1894        .step = 1,
1895        .def = 0,
1896};
1897
1898static const struct v4l2_ctrl_config vpfe_isif_cgrgain = {
1899        .ops = &vpfe_isif_ctrl_ops,
1900        .id = VPFE_ISIF_CID_CGRGAIN,
1901        .name = "CGRGAIN",
1902        .type = V4L2_CTRL_TYPE_INTEGER,
1903        .min = 0,
1904        .max = (1 << 12) - 1,
1905        .step = 1,
1906        .def = 0,
1907};
1908
1909static const struct v4l2_ctrl_config vpfe_isif_cgbgain = {
1910        .ops = &vpfe_isif_ctrl_ops,
1911        .id = VPFE_ISIF_CID_CGBGAIN,
1912        .name = "CGBGAIN",
1913        .type = V4L2_CTRL_TYPE_INTEGER,
1914        .min = 0,
1915        .max = (1 << 12) - 1,
1916        .step = 1,
1917        .def = 0,
1918};
1919
1920static const struct v4l2_ctrl_config vpfe_isif_cbgain = {
1921        .ops = &vpfe_isif_ctrl_ops,
1922        .id = VPFE_ISIF_CID_CBGAIN,
1923        .name = "CBGAIN",
1924        .type = V4L2_CTRL_TYPE_INTEGER,
1925        .min = 0,
1926        .max = (1 << 12) - 1,
1927        .step = 1,
1928        .def = 0,
1929};
1930
1931static const struct v4l2_ctrl_config vpfe_isif_gain_offset = {
1932        .ops = &vpfe_isif_ctrl_ops,
1933        .id = VPFE_ISIF_CID_GAIN_OFFSET,
1934        .name = "Gain Offset",
1935        .type = V4L2_CTRL_TYPE_INTEGER,
1936        .min = 0,
1937        .max = (1 << 12) - 1,
1938        .step = 1,
1939        .def = 0,
1940};
1941
1942static void isif_remove(struct vpfe_isif_device *isif,
1943                        struct platform_device *pdev)
1944{
1945        struct resource *res;
1946        int i = 0;
1947
1948        iounmap(isif->isif_cfg.base_addr);
1949        iounmap(isif->isif_cfg.linear_tbl0_addr);
1950        iounmap(isif->isif_cfg.linear_tbl1_addr);
1951
1952        while (i < 3) {
1953                res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1954                if (res)
1955                        release_mem_region(res->start,
1956                                           resource_size(res));
1957                i++;
1958        }
1959}
1960
1961static void isif_config_defaults(struct vpfe_isif_device *isif)
1962{
1963        isif->isif_cfg.ycbcr.v4l2_pix_fmt = V4L2_PIX_FMT_UYVY;
1964        isif->isif_cfg.ycbcr.pix_fmt = ISIF_PIXFMT_YCBCR_8BIT;
1965        isif->isif_cfg.ycbcr.frm_fmt = ISIF_FRMFMT_INTERLACED;
1966        isif->isif_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE;
1967        isif->isif_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE;
1968        isif->isif_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE;
1969        isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY;
1970        isif->isif_cfg.ycbcr.buf_type = ISIF_BUFTYPE_FLD_INTERLEAVED;
1971
1972        isif->isif_cfg.bayer.v4l2_pix_fmt = V4L2_PIX_FMT_SGRBG10ALAW8;
1973        isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW;
1974        isif->isif_cfg.bayer.frm_fmt = ISIF_FRMFMT_PROGRESSIVE;
1975        isif->isif_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE;
1976        isif->isif_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE;
1977        isif->isif_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE;
1978        isif->isif_cfg.bayer.cfa_pat = ISIF_CFA_PAT_MOSAIC;
1979        isif->isif_cfg.bayer.data_msb = ISIF_BIT_MSB_11;
1980        isif->isif_cfg.data_pack = ISIF_PACK_8BIT;
1981}
1982/*
1983 * vpfe_isif_init() - Initialize V4L2 subdev and media entity
1984 * @isif: VPFE isif module
1985 * @pdev: Pointer to platform device structure.
1986 * Return 0 on success and a negative error code on failure.
1987 */
1988int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev)
1989{
1990        struct v4l2_subdev *sd = &isif->subdev;
1991        struct media_pad *pads = &isif->pads[0];
1992        struct media_entity *me = &sd->entity;
1993        static resource_size_t res_len;
1994        struct resource *res;
1995        void *__iomem addr;
1996        int status;
1997        int i = 0;
1998
1999        /* Get the ISIF base address, linearization table0 and table1 addr. */
2000        while (i < 3) {
2001                res = platform_get_resource(pdev, IORESOURCE_MEM, i);
2002                if (!res) {
2003                        status = -ENOENT;
2004                        goto fail_nobase_res;
2005                }
2006                res_len = resource_size(res);
2007                res = request_mem_region(res->start, res_len, res->name);
2008                if (!res) {
2009                        status = -EBUSY;
2010                        goto fail_nobase_res;
2011                }
2012                addr = ioremap_nocache(res->start, res_len);
2013                if (!addr) {
2014                        status = -EBUSY;
2015                        goto fail_base_iomap;
2016                }
2017                switch (i) {
2018                case 0:
2019                        /* ISIF base address */
2020                        isif->isif_cfg.base_addr = addr;
2021                        break;
2022                case 1:
2023                        /* ISIF linear tbl0 address */
2024                        isif->isif_cfg.linear_tbl0_addr = addr;
2025                        break;
2026                default:
2027                        /* ISIF linear tbl0 address */
2028                        isif->isif_cfg.linear_tbl1_addr = addr;
2029                        break;
2030                }
2031                i++;
2032        }
2033        davinci_cfg_reg(DM365_VIN_CAM_WEN);
2034        davinci_cfg_reg(DM365_VIN_CAM_VD);
2035        davinci_cfg_reg(DM365_VIN_CAM_HD);
2036        davinci_cfg_reg(DM365_VIN_YIN4_7_EN);
2037        davinci_cfg_reg(DM365_VIN_YIN0_3_EN);
2038
2039        /* queue ops */
2040        isif->video_out.ops = &isif_video_ops;
2041        v4l2_subdev_init(sd, &isif_v4l2_ops);
2042        sd->internal_ops = &isif_v4l2_internal_ops;
2043        strlcpy(sd->name, "DAVINCI ISIF", sizeof(sd->name));
2044        sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
2045        v4l2_set_subdevdata(sd, isif);
2046        sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
2047        pads[ISIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
2048        pads[ISIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
2049
2050        isif->input = ISIF_INPUT_NONE;
2051        isif->output = ISIF_OUTPUT_NONE;
2052        me->ops = &isif_media_ops;
2053        status = media_entity_init(me, ISIF_PADS_NUM, pads, 0);
2054        if (status)
2055                goto isif_fail;
2056        isif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2057        status = vpfe_video_init(&isif->video_out, "ISIF");
2058        if (status) {
2059                pr_err("Failed to init isif-out video device\n");
2060                goto isif_fail;
2061        }
2062        v4l2_ctrl_handler_init(&isif->ctrls, 6);
2063        v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_crgain, NULL);
2064        v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgrgain, NULL);
2065        v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgbgain, NULL);
2066        v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cbgain, NULL);
2067        v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_gain_offset, NULL);
2068        v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_dpcm_pred, NULL);
2069
2070        v4l2_ctrl_handler_setup(&isif->ctrls);
2071        sd->ctrl_handler = &isif->ctrls;
2072        isif_config_defaults(isif);
2073        return 0;
2074fail_base_iomap:
2075        release_mem_region(res->start, res_len);
2076        i--;
2077fail_nobase_res:
2078        if (isif->isif_cfg.base_addr)
2079                iounmap(isif->isif_cfg.base_addr);
2080        if (isif->isif_cfg.linear_tbl0_addr)
2081                iounmap(isif->isif_cfg.linear_tbl0_addr);
2082
2083        while (i >= 0) {
2084                res = platform_get_resource(pdev, IORESOURCE_MEM, i);
2085                release_mem_region(res->start, res_len);
2086                i--;
2087        }
2088        return status;
2089isif_fail:
2090        v4l2_ctrl_handler_free(&isif->ctrls);
2091        isif_remove(isif, pdev);
2092        return status;
2093}
2094
2095/*
2096 * vpfe_isif_cleanup - isif module cleanup
2097 * @isif: pointer to isif subdevice
2098 * @dev: pointer to platform device structure
2099 */
2100void
2101vpfe_isif_cleanup(struct vpfe_isif_device *isif, struct platform_device *pdev)
2102{
2103        isif_remove(isif, pdev);
2104}
2105