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