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