linux/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Texas Instruments Inc
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public License as
   6 * published by the Free Software Foundation version 2.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public License
  14 * along with this program; if not, write to the Free Software
  15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  16 *
  17 * Contributors:
  18 *      Manjunath Hadli <manjunath.hadli@ti.com>
  19 *      Prabhakar Lad <prabhakar.lad@ti.com>
  20 */
  21
  22#include "dm365_ipipeif.h"
  23#include "vpfe_mc_capture.h"
  24
  25static const unsigned int ipipeif_input_fmts[] = {
  26        V4L2_MBUS_FMT_UYVY8_2X8,
  27        V4L2_MBUS_FMT_SGRBG12_1X12,
  28        V4L2_MBUS_FMT_Y8_1X8,
  29        V4L2_MBUS_FMT_UV8_1X8,
  30        V4L2_MBUS_FMT_YDYUYDYV8_1X16,
  31        V4L2_MBUS_FMT_SBGGR8_1X8,
  32};
  33
  34static const unsigned int ipipeif_output_fmts[] = {
  35        V4L2_MBUS_FMT_UYVY8_2X8,
  36        V4L2_MBUS_FMT_SGRBG12_1X12,
  37        V4L2_MBUS_FMT_Y8_1X8,
  38        V4L2_MBUS_FMT_UV8_1X8,
  39        V4L2_MBUS_FMT_YDYUYDYV8_1X16,
  40        V4L2_MBUS_FMT_SBGGR8_1X8,
  41        V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
  42        V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8,
  43};
  44
  45static int
  46ipipeif_get_pack_mode(enum v4l2_mbus_pixelcode in_pix_fmt)
  47{
  48        switch (in_pix_fmt) {
  49        case V4L2_MBUS_FMT_SBGGR8_1X8:
  50        case V4L2_MBUS_FMT_Y8_1X8:
  51        case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
  52        case V4L2_MBUS_FMT_UV8_1X8:
  53                return IPIPEIF_5_1_PACK_8_BIT;
  54
  55        case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
  56                return IPIPEIF_5_1_PACK_8_BIT_A_LAW;
  57
  58        case V4L2_MBUS_FMT_SGRBG12_1X12:
  59                return IPIPEIF_5_1_PACK_16_BIT;
  60
  61        case V4L2_MBUS_FMT_SBGGR12_1X12:
  62                return IPIPEIF_5_1_PACK_12_BIT;
  63
  64        default:
  65                return IPIPEIF_5_1_PACK_16_BIT;
  66        }
  67}
  68
  69static inline u32 ipipeif_read(void *addr, u32 offset)
  70{
  71        return readl(addr + offset);
  72}
  73
  74static inline void ipipeif_write(u32 val, void *addr, u32 offset)
  75{
  76        writel(val, addr + offset);
  77}
  78
  79static void ipipeif_config_dpc(void *addr, struct ipipeif_dpc *dpc)
  80{
  81        u32 val = 0;
  82
  83        if (dpc->en) {
  84                val = (dpc->en & 1) << IPIPEIF_DPC2_EN_SHIFT;
  85                val |= dpc->thr & IPIPEIF_DPC2_THR_MASK;
  86        }
  87        ipipeif_write(val, addr, IPIPEIF_DPC2);
  88}
  89
  90#define IPIPEIF_MODE_CONTINUOUS                 0
  91#define IPIPEIF_MODE_ONE_SHOT                   1
  92
  93static int get_oneshot_mode(enum ipipeif_input_entity input)
  94{
  95        if (input == IPIPEIF_INPUT_MEMORY)
  96                return IPIPEIF_MODE_ONE_SHOT;
  97        else if (input == IPIPEIF_INPUT_ISIF)
  98                return IPIPEIF_MODE_CONTINUOUS;
  99
 100        return -EINVAL;
 101}
 102
 103static int
 104ipipeif_get_cfg_src1(struct vpfe_ipipeif_device *ipipeif)
 105{
 106        struct v4l2_mbus_framefmt *informat;
 107
 108        informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
 109        if (ipipeif->input == IPIPEIF_INPUT_MEMORY &&
 110           (informat->code == V4L2_MBUS_FMT_Y8_1X8 ||
 111            informat->code == V4L2_MBUS_FMT_UV8_1X8))
 112                return IPIPEIF_CCDC;
 113
 114        return IPIPEIF_SRC1_PARALLEL_PORT;
 115}
 116
 117static int
 118ipipeif_get_data_shift(struct vpfe_ipipeif_device *ipipeif)
 119{
 120        struct v4l2_mbus_framefmt *informat;
 121
 122        informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
 123
 124        switch (informat->code) {
 125        case V4L2_MBUS_FMT_SGRBG12_1X12:
 126                return IPIPEIF_5_1_BITS11_0;
 127
 128        case V4L2_MBUS_FMT_Y8_1X8:
 129        case V4L2_MBUS_FMT_UV8_1X8:
 130                return IPIPEIF_5_1_BITS11_0;
 131
 132        default:
 133                return IPIPEIF_5_1_BITS7_0;
 134        }
 135}
 136
 137static enum ipipeif_input_source
 138ipipeif_get_source(struct vpfe_ipipeif_device *ipipeif)
 139{
 140        struct v4l2_mbus_framefmt *informat;
 141
 142        informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
 143        if (ipipeif->input == IPIPEIF_INPUT_ISIF)
 144                return IPIPEIF_CCDC;
 145
 146        if (informat->code == V4L2_MBUS_FMT_UYVY8_2X8)
 147                return IPIPEIF_SDRAM_YUV;
 148
 149        return IPIPEIF_SDRAM_RAW;
 150}
 151
 152void vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device *ipipeif)
 153{
 154        struct vpfe_video_device *video_in = &ipipeif->video_in;
 155
 156        if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
 157                return;
 158
 159        spin_lock(&video_in->dma_queue_lock);
 160        vpfe_video_process_buffer_complete(video_in);
 161        video_in->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
 162        vpfe_video_schedule_next_buffer(video_in);
 163        spin_unlock(&video_in->dma_queue_lock);
 164}
 165
 166int vpfe_ipipeif_decimation_enabled(struct vpfe_device *vpfe_dev)
 167{
 168        struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
 169
 170        return ipipeif->config.decimation;
 171}
 172
 173int vpfe_ipipeif_get_rsz(struct vpfe_device *vpfe_dev)
 174{
 175        struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
 176
 177        return ipipeif->config.rsz;
 178}
 179
 180#define RD_DATA_15_2            0x7
 181
 182/*
 183 * ipipeif_hw_setup() - This function sets up IPIPEIF
 184 * @sd: pointer to v4l2 subdev structure
 185 * return -EINVAL or zero on success
 186 */
 187static int ipipeif_hw_setup(struct v4l2_subdev *sd)
 188{
 189        struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
 190        struct v4l2_mbus_framefmt *informat, *outformat;
 191        struct ipipeif_params params = ipipeif->config;
 192        enum ipipeif_input_source ipipeif_source;
 193        enum v4l2_mbus_pixelcode isif_port_if;
 194        void *ipipeif_base_addr;
 195        unsigned int val;
 196        int data_shift;
 197        int pack_mode;
 198        int source1;
 199
 200        ipipeif_base_addr = ipipeif->ipipeif_base_addr;
 201
 202        /* Enable clock to IPIPEIF and IPIPE */
 203        vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
 204
 205        informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
 206        outformat = &ipipeif->formats[IPIPEIF_PAD_SOURCE];
 207
 208        /* Combine all the fields to make CFG1 register of IPIPEIF */
 209        val = get_oneshot_mode(ipipeif->input);
 210        if (val < 0) {
 211                pr_err("ipipeif: links setup required");
 212                return -EINVAL;
 213        }
 214        val = val << ONESHOT_SHIFT;
 215
 216        ipipeif_source = ipipeif_get_source(ipipeif);
 217        val |= ipipeif_source << INPSRC_SHIFT;
 218
 219        val |= params.clock_select << CLKSEL_SHIFT;
 220        val |= params.avg_filter << AVGFILT_SHIFT;
 221        val |= params.decimation << DECIM_SHIFT;
 222
 223        pack_mode = ipipeif_get_pack_mode(informat->code);
 224        val |= pack_mode << PACK8IN_SHIFT;
 225
 226        source1 = ipipeif_get_cfg_src1(ipipeif);
 227        val |= source1 << INPSRC1_SHIFT;
 228
 229        data_shift = ipipeif_get_data_shift(ipipeif);
 230        if (ipipeif_source != IPIPEIF_SDRAM_YUV)
 231                val |= data_shift << DATASFT_SHIFT;
 232        else
 233                val &= ~(RD_DATA_15_2 << DATASFT_SHIFT);
 234
 235        ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG1);
 236
 237        switch (ipipeif_source) {
 238        case IPIPEIF_CCDC:
 239                ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN);
 240                break;
 241
 242        case IPIPEIF_SDRAM_RAW:
 243        case IPIPEIF_CCDC_DARKFM:
 244                ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN);
 245                /* fall through */
 246        case IPIPEIF_SDRAM_YUV:
 247                val |= data_shift << DATASFT_SHIFT;
 248                ipipeif_write(params.ppln, ipipeif_base_addr, IPIPEIF_PPLN);
 249                ipipeif_write(params.lpfr, ipipeif_base_addr, IPIPEIF_LPFR);
 250                ipipeif_write(informat->width, ipipeif_base_addr, IPIPEIF_HNUM);
 251                ipipeif_write(informat->height,
 252                              ipipeif_base_addr, IPIPEIF_VNUM);
 253                break;
 254
 255        default:
 256                return -EINVAL;
 257        }
 258
 259        /*check if decimation is enable or not */
 260        if (params.decimation)
 261                ipipeif_write(params.rsz, ipipeif_base_addr, IPIPEIF_RSZ);
 262
 263        /* Setup sync alignment and initial rsz position */
 264        val = params.if_5_1.align_sync & 1;
 265        val <<= IPIPEIF_INIRSZ_ALNSYNC_SHIFT;
 266        val |= params.if_5_1.rsz_start & IPIPEIF_INIRSZ_MASK;
 267        ipipeif_write(val, ipipeif_base_addr, IPIPEIF_INIRSZ);
 268        isif_port_if = informat->code;
 269
 270        if (isif_port_if == V4L2_MBUS_FMT_Y8_1X8)
 271                isif_port_if = V4L2_MBUS_FMT_YUYV8_1X16;
 272        else if (isif_port_if == V4L2_MBUS_FMT_UV8_1X8)
 273                isif_port_if = V4L2_MBUS_FMT_SGRBG12_1X12;
 274
 275        /* Enable DPCM decompression */
 276        switch (ipipeif_source) {
 277        case IPIPEIF_SDRAM_RAW:
 278                val = 0;
 279                if (outformat->code == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) {
 280                        val = 1;
 281                        val |= (IPIPEIF_DPCM_8BIT_10BIT & 1) <<
 282                                IPIPEIF_DPCM_BITS_SHIFT;
 283                        val |= (ipipeif->dpcm_predictor & 1) <<
 284                                IPIPEIF_DPCM_PRED_SHIFT;
 285                }
 286                ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DPCM);
 287
 288                /* set DPC */
 289                ipipeif_config_dpc(ipipeif_base_addr, &params.if_5_1.dpc);
 290
 291                ipipeif_write(params.if_5_1.clip,
 292                              ipipeif_base_addr, IPIPEIF_OCLIP);
 293
 294                /* fall through for SDRAM YUV mode */
 295                /* configure CFG2 */
 296                val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CFG2);
 297                switch (isif_port_if) {
 298                case V4L2_MBUS_FMT_YUYV8_1X16:
 299                case V4L2_MBUS_FMT_UYVY8_2X8:
 300                case V4L2_MBUS_FMT_Y8_1X8:
 301                        RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
 302                        SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
 303                        ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
 304                        break;
 305
 306                default:
 307                        RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
 308                        RESETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
 309                        ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
 310                        break;
 311                }
 312
 313        case IPIPEIF_SDRAM_YUV:
 314                /* Set clock divider */
 315                if (params.clock_select == IPIPEIF_SDRAM_CLK) {
 316                        val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CLKDIV);
 317                        val |= (params.if_5_1.clk_div.m - 1) <<
 318                                IPIPEIF_CLKDIV_M_SHIFT;
 319                        val |= (params.if_5_1.clk_div.n - 1);
 320                        ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CLKDIV);
 321                }
 322                break;
 323
 324        case IPIPEIF_CCDC:
 325        case IPIPEIF_CCDC_DARKFM:
 326                /* set DPC */
 327                ipipeif_config_dpc(ipipeif_base_addr, &params.if_5_1.dpc);
 328
 329                /* Set DF gain & threshold control */
 330                val = 0;
 331                if (params.if_5_1.df_gain_en) {
 332                        val = params.if_5_1.df_gain_thr &
 333                                IPIPEIF_DF_GAIN_THR_MASK;
 334                        ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGTH);
 335                        val = (params.if_5_1.df_gain_en & 1) <<
 336                                IPIPEIF_DF_GAIN_EN_SHIFT;
 337                        val |= params.if_5_1.df_gain &
 338                                IPIPEIF_DF_GAIN_MASK;
 339                }
 340                ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGVL);
 341                /* configure CFG2 */
 342                val = VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_HDPOL_SHIFT;
 343                val |= VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_VDPOL_SHIFT;
 344
 345                switch (isif_port_if) {
 346                case V4L2_MBUS_FMT_YUYV8_1X16:
 347                case V4L2_MBUS_FMT_YUYV10_1X20:
 348                        RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
 349                        SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
 350                        break;
 351
 352                case V4L2_MBUS_FMT_YUYV8_2X8:
 353                case V4L2_MBUS_FMT_UYVY8_2X8:
 354                case V4L2_MBUS_FMT_Y8_1X8:
 355                case V4L2_MBUS_FMT_YUYV10_2X10:
 356                        SETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
 357                        SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
 358                        val |= IPIPEIF_CBCR_Y << IPIPEIF_CFG2_YUV8P_SHIFT;
 359                        break;
 360
 361                default:
 362                        /* Bayer */
 363                        ipipeif_write(params.if_5_1.clip, ipipeif_base_addr,
 364                                IPIPEIF_OCLIP);
 365                }
 366                ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
 367                break;
 368
 369        default:
 370                return -EINVAL;
 371        }
 372
 373        return 0;
 374}
 375
 376static int
 377ipipeif_set_config(struct v4l2_subdev *sd, struct ipipeif_params *config)
 378{
 379        struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
 380        struct device *dev = ipipeif->subdev.v4l2_dev->dev;
 381
 382        if (!config) {
 383                dev_err(dev, "Invalid configuration pointer\n");
 384                return -EINVAL;
 385        }
 386
 387        ipipeif->config.clock_select = config->clock_select;
 388        ipipeif->config.ppln = config->ppln;
 389        ipipeif->config.lpfr = config->lpfr;
 390        ipipeif->config.rsz = config->rsz;
 391        ipipeif->config.decimation = config->decimation;
 392        if (ipipeif->config.decimation &&
 393           (ipipeif->config.rsz < IPIPEIF_RSZ_MIN ||
 394            ipipeif->config.rsz > IPIPEIF_RSZ_MAX)) {
 395                dev_err(dev, "rsz range is %d to %d\n",
 396                        IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
 397                return -EINVAL;
 398        }
 399
 400        ipipeif->config.avg_filter = config->avg_filter;
 401
 402        ipipeif->config.if_5_1.df_gain_thr = config->if_5_1.df_gain_thr;
 403        ipipeif->config.if_5_1.df_gain = config->if_5_1.df_gain;
 404        ipipeif->config.if_5_1.df_gain_en = config->if_5_1.df_gain_en;
 405
 406        ipipeif->config.if_5_1.rsz_start = config->if_5_1.rsz_start;
 407        ipipeif->config.if_5_1.align_sync = config->if_5_1.align_sync;
 408        ipipeif->config.if_5_1.clip = config->if_5_1.clip;
 409
 410        ipipeif->config.if_5_1.dpc.en = config->if_5_1.dpc.en;
 411        ipipeif->config.if_5_1.dpc.thr = config->if_5_1.dpc.thr;
 412
 413        ipipeif->config.if_5_1.clk_div.m = config->if_5_1.clk_div.m;
 414        ipipeif->config.if_5_1.clk_div.n = config->if_5_1.clk_div.n;
 415
 416        return 0;
 417}
 418
 419static int
 420ipipeif_get_config(struct v4l2_subdev *sd, void __user *arg)
 421{
 422        struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
 423        struct ipipeif_params *config = (struct ipipeif_params *)arg;
 424        struct device *dev = ipipeif->subdev.v4l2_dev->dev;
 425
 426        if (!arg) {
 427                dev_err(dev, "Invalid configuration pointer\n");
 428                return -EINVAL;
 429        }
 430
 431        config->clock_select = ipipeif->config.clock_select;
 432        config->ppln = ipipeif->config.ppln;
 433        config->lpfr = ipipeif->config.lpfr;
 434        config->rsz = ipipeif->config.rsz;
 435        config->decimation = ipipeif->config.decimation;
 436        config->avg_filter = ipipeif->config.avg_filter;
 437
 438        config->if_5_1.df_gain_thr = ipipeif->config.if_5_1.df_gain_thr;
 439        config->if_5_1.df_gain = ipipeif->config.if_5_1.df_gain;
 440        config->if_5_1.df_gain_en = ipipeif->config.if_5_1.df_gain_en;
 441
 442        config->if_5_1.rsz_start = ipipeif->config.if_5_1.rsz_start;
 443        config->if_5_1.align_sync = ipipeif->config.if_5_1.align_sync;
 444        config->if_5_1.clip = ipipeif->config.if_5_1.clip;
 445
 446        config->if_5_1.dpc.en = ipipeif->config.if_5_1.dpc.en;
 447        config->if_5_1.dpc.thr = ipipeif->config.if_5_1.dpc.thr;
 448
 449        config->if_5_1.clk_div.m = ipipeif->config.if_5_1.clk_div.m;
 450        config->if_5_1.clk_div.n = ipipeif->config.if_5_1.clk_div.n;
 451
 452        return 0;
 453}
 454
 455/*
 456 * ipipeif_ioctl() - Handle ipipeif module private ioctl's
 457 * @sd: pointer to v4l2 subdev structure
 458 * @cmd: configuration command
 459 * @arg: configuration argument
 460 */
 461static long ipipeif_ioctl(struct v4l2_subdev *sd,
 462                          unsigned int cmd, void *arg)
 463{
 464        struct ipipeif_params *config = (struct ipipeif_params *)arg;
 465        int ret = -ENOIOCTLCMD;
 466
 467        switch (cmd) {
 468        case VIDIOC_VPFE_IPIPEIF_S_CONFIG:
 469                ret = ipipeif_set_config(sd, config);
 470                break;
 471
 472        case VIDIOC_VPFE_IPIPEIF_G_CONFIG:
 473                ret = ipipeif_get_config(sd, arg);
 474                break;
 475        }
 476        return ret;
 477}
 478
 479/*
 480 * ipipeif_s_ctrl() - Handle set control subdev method
 481 * @ctrl: pointer to v4l2 control structure
 482 */
 483static int ipipeif_s_ctrl(struct v4l2_ctrl *ctrl)
 484{
 485        struct vpfe_ipipeif_device *ipipeif =
 486                container_of(ctrl->handler, struct vpfe_ipipeif_device, ctrls);
 487
 488        switch (ctrl->id) {
 489        case VPFE_CID_DPCM_PREDICTOR:
 490                ipipeif->dpcm_predictor = ctrl->val;
 491                break;
 492
 493        case V4L2_CID_GAIN:
 494                ipipeif->gain = ctrl->val;
 495                break;
 496
 497        default:
 498                return -EINVAL;
 499        }
 500
 501        return 0;
 502}
 503
 504#define ENABLE_IPIPEIF          0x1
 505
 506void vpfe_ipipeif_enable(struct vpfe_device *vpfe_dev)
 507{
 508        struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
 509        void *ipipeif_base_addr = ipipeif->ipipeif_base_addr;
 510        unsigned char val;
 511
 512        if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
 513                return;
 514
 515        do {
 516                val = ipipeif_read(ipipeif_base_addr, IPIPEIF_ENABLE);
 517        } while (val & 0x1);
 518
 519        ipipeif_write(ENABLE_IPIPEIF, ipipeif_base_addr, IPIPEIF_ENABLE);
 520}
 521
 522/*
 523 * ipipeif_set_stream() - Enable/Disable streaming on ipipeif subdev
 524 * @sd: pointer to v4l2 subdev structure
 525 * @enable: 1 == Enable, 0 == Disable
 526 */
 527static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable)
 528{
 529        struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
 530        struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif);
 531        int ret = 0;
 532
 533        if (!enable)
 534                return ret;
 535
 536        ret = ipipeif_hw_setup(sd);
 537        if (!ret)
 538                vpfe_ipipeif_enable(vpfe_dev);
 539
 540        return ret;
 541}
 542
 543/*
 544 * ipipeif_enum_mbus_code() - Handle pixel format enumeration
 545 * @sd: pointer to v4l2 subdev structure
 546 * @fh: V4L2 subdev file handle
 547 * @code: pointer to v4l2_subdev_mbus_code_enum structure
 548 * return -EINVAL or zero on success
 549 */
 550static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
 551                                  struct v4l2_subdev_fh *fh,
 552                        struct v4l2_subdev_mbus_code_enum *code)
 553{
 554        switch (code->pad) {
 555        case IPIPEIF_PAD_SINK:
 556                if (code->index >= ARRAY_SIZE(ipipeif_input_fmts))
 557                        return -EINVAL;
 558
 559                code->code = ipipeif_input_fmts[code->index];
 560                break;
 561
 562        case IPIPEIF_PAD_SOURCE:
 563                if (code->index >= ARRAY_SIZE(ipipeif_output_fmts))
 564                        return -EINVAL;
 565
 566                code->code = ipipeif_output_fmts[code->index];
 567                break;
 568
 569        default:
 570                return -EINVAL;
 571        }
 572
 573        return 0;
 574}
 575
 576/*
 577 * ipipeif_get_format() - Handle get format by pads subdev method
 578 * @sd: pointer to v4l2 subdev structure
 579 * @fh: V4L2 subdev file handle
 580 * @fmt: pointer to v4l2 subdev format structure
 581 */
 582static int
 583ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 584                struct v4l2_subdev_format *fmt)
 585{
 586        struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
 587
 588        if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 589                fmt->format = ipipeif->formats[fmt->pad];
 590        else
 591                fmt->format = *(v4l2_subdev_get_try_format(fh, fmt->pad));
 592
 593        return 0;
 594}
 595
 596#define MIN_OUT_WIDTH                   32
 597#define MIN_OUT_HEIGHT                  32
 598
 599/*
 600 * ipipeif_try_format() - Handle try format by pad subdev method
 601 * @ipipeif: VPFE ipipeif device.
 602 * @fh: V4L2 subdev file handle.
 603 * @pad: pad num.
 604 * @fmt: pointer to v4l2 format structure.
 605 * @which : wanted subdev format
 606 */
 607static void
 608ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif,
 609                   struct v4l2_subdev_fh *fh, unsigned int pad,
 610                   struct v4l2_mbus_framefmt *fmt,
 611                   enum v4l2_subdev_format_whence which)
 612{
 613        unsigned int max_out_height;
 614        unsigned int max_out_width;
 615        unsigned int i;
 616
 617        max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A;
 618        max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A;
 619
 620        if (pad == IPIPEIF_PAD_SINK) {
 621                for (i = 0; i < ARRAY_SIZE(ipipeif_input_fmts); i++)
 622                        if (fmt->code == ipipeif_input_fmts[i])
 623                                break;
 624
 625                /* If not found, use SBGGR10 as default */
 626                if (i >= ARRAY_SIZE(ipipeif_input_fmts))
 627                        fmt->code = V4L2_MBUS_FMT_SGRBG12_1X12;
 628        } else if (pad == IPIPEIF_PAD_SOURCE) {
 629                for (i = 0; i < ARRAY_SIZE(ipipeif_output_fmts); i++)
 630                        if (fmt->code == ipipeif_output_fmts[i])
 631                                break;
 632
 633                /* If not found, use UYVY as default */
 634                if (i >= ARRAY_SIZE(ipipeif_output_fmts))
 635                        fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
 636        }
 637
 638        fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width);
 639        fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height);
 640}
 641
 642static int
 643ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 644                     struct v4l2_subdev_frame_size_enum *fse)
 645{
 646        struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
 647        struct v4l2_mbus_framefmt format;
 648
 649        if (fse->index != 0)
 650                return -EINVAL;
 651
 652        format.code = fse->code;
 653        format.width = 1;
 654        format.height = 1;
 655        ipipeif_try_format(ipipeif, fh, fse->pad, &format,
 656                           V4L2_SUBDEV_FORMAT_TRY);
 657        fse->min_width = format.width;
 658        fse->min_height = format.height;
 659
 660        if (format.code != fse->code)
 661                return -EINVAL;
 662
 663        format.code = fse->code;
 664        format.width = -1;
 665        format.height = -1;
 666        ipipeif_try_format(ipipeif, fh, fse->pad, &format,
 667                           V4L2_SUBDEV_FORMAT_TRY);
 668        fse->max_width = format.width;
 669        fse->max_height = format.height;
 670
 671        return 0;
 672}
 673
 674/*
 675 * __ipipeif_get_format() - helper function for getting ipipeif format
 676 * @ipipeif: pointer to ipipeif private structure.
 677 * @pad: pad number.
 678 * @fh: V4L2 subdev file handle.
 679 * @which: wanted subdev format.
 680 *
 681 */
 682static struct v4l2_mbus_framefmt *
 683__ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif,
 684                       struct v4l2_subdev_fh *fh, unsigned int pad,
 685                       enum v4l2_subdev_format_whence which)
 686{
 687        if (which == V4L2_SUBDEV_FORMAT_TRY)
 688                return v4l2_subdev_get_try_format(fh, pad);
 689
 690        return &ipipeif->formats[pad];
 691}
 692
 693/*
 694 * ipipeif_set_format() - Handle set format by pads subdev method
 695 * @sd: pointer to v4l2 subdev structure
 696 * @fh: V4L2 subdev file handle
 697 * @fmt: pointer to v4l2 subdev format structure
 698 * return -EINVAL or zero on success
 699 */
 700static int
 701ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 702                struct v4l2_subdev_format *fmt)
 703{
 704        struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
 705        struct v4l2_mbus_framefmt *format;
 706
 707        format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which);
 708        if (format == NULL)
 709                return -EINVAL;
 710
 711        ipipeif_try_format(ipipeif, fh, fmt->pad, &fmt->format, fmt->which);
 712        *format = fmt->format;
 713
 714        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
 715                return 0;
 716
 717        if (fmt->pad == IPIPEIF_PAD_SINK &&
 718            ipipeif->input != IPIPEIF_INPUT_NONE)
 719                ipipeif->formats[fmt->pad] = fmt->format;
 720        else if (fmt->pad == IPIPEIF_PAD_SOURCE &&
 721                 ipipeif->output != IPIPEIF_OUTPUT_NONE)
 722                ipipeif->formats[fmt->pad] = fmt->format;
 723        else
 724                return -EINVAL;
 725
 726        return 0;
 727}
 728
 729static void ipipeif_set_default_config(struct vpfe_ipipeif_device *ipipeif)
 730{
 731#define WIDTH_I                 640
 732#define HEIGHT_I                480
 733
 734        const struct ipipeif_params ipipeif_defaults = {
 735                .clock_select = IPIPEIF_SDRAM_CLK,
 736                .ppln = WIDTH_I + 8,
 737                .lpfr = HEIGHT_I + 10,
 738                .rsz = 16,      /* resize ratio 16/rsz */
 739                .decimation = IPIPEIF_DECIMATION_OFF,
 740                .avg_filter = IPIPEIF_AVG_OFF,
 741                .if_5_1 = {
 742                        .clk_div = {
 743                                .m = 1, /* clock = sdram clock * (m/n) */
 744                                .n = 6
 745                        },
 746                        .clip = 4095,
 747                },
 748        };
 749        memset(&ipipeif->config, 0, sizeof(struct ipipeif_params));
 750        memcpy(&ipipeif->config, &ipipeif_defaults,
 751               sizeof(struct ipipeif_params));
 752}
 753
 754/*
 755 * ipipeif_init_formats() - Initialize formats on all pads
 756 * @sd: VPFE ipipeif V4L2 subdevice
 757 * @fh: V4L2 subdev file handle
 758 *
 759 * Initialize all pad formats with default values. If fh is not NULL, try
 760 * formats are initialized on the file handle. Otherwise active formats are
 761 * initialized on the device.
 762 */
 763static int
 764ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 765{
 766        struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
 767        struct v4l2_subdev_format format;
 768
 769        memset(&format, 0, sizeof(format));
 770        format.pad = IPIPEIF_PAD_SINK;
 771        format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
 772        format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
 773        format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
 774        format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
 775        ipipeif_set_format(sd, fh, &format);
 776
 777        memset(&format, 0, sizeof(format));
 778        format.pad = IPIPEIF_PAD_SOURCE;
 779        format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
 780        format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
 781        format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
 782        format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
 783        ipipeif_set_format(sd, fh, &format);
 784
 785        ipipeif_set_default_config(ipipeif);
 786
 787        return 0;
 788}
 789
 790/*
 791 * ipipeif_video_in_queue() - ipipeif video in queue
 792 * @vpfe_dev: vpfe device pointer
 793 * @addr: buffer address
 794 */
 795static int
 796ipipeif_video_in_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
 797{
 798        struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif;
 799        void *ipipeif_base_addr = ipipeif->ipipeif_base_addr;
 800        unsigned int adofs;
 801        u32 val;
 802
 803        if (ipipeif->input != IPIPEIF_INPUT_MEMORY)
 804                return -EINVAL;
 805
 806        switch (ipipeif->formats[IPIPEIF_PAD_SINK].code) {
 807        case V4L2_MBUS_FMT_Y8_1X8:
 808        case V4L2_MBUS_FMT_UV8_1X8:
 809        case V4L2_MBUS_FMT_YDYUYDYV8_1X16:
 810                adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width;
 811                break;
 812
 813        default:
 814                adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width << 1;
 815                break;
 816        }
 817
 818        /* adjust the line len to be a multiple of 32 */
 819        adofs += 31;
 820        adofs &= ~0x1f;
 821        val = (adofs >> 5) & IPIPEIF_ADOFS_LSB_MASK;
 822        ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADOFS);
 823
 824        /* lower sixteen bit */
 825        val = (addr >> IPIPEIF_ADDRL_SHIFT) & IPIPEIF_ADDRL_MASK;
 826        ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRL);
 827
 828        /* upper next seven bit */
 829        val = (addr >> IPIPEIF_ADDRU_SHIFT) & IPIPEIF_ADDRU_MASK;
 830        ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRU);
 831
 832        return 0;
 833}
 834
 835/* subdev core operations */
 836static const struct v4l2_subdev_core_ops ipipeif_v4l2_core_ops = {
 837        .ioctl = ipipeif_ioctl,
 838};
 839
 840static const struct v4l2_ctrl_ops ipipeif_ctrl_ops = {
 841        .s_ctrl = ipipeif_s_ctrl,
 842};
 843
 844static const struct v4l2_ctrl_config vpfe_ipipeif_dpcm_pred = {
 845        .ops = &ipipeif_ctrl_ops,
 846        .id = VPFE_CID_DPCM_PREDICTOR,
 847        .name = "DPCM Predictor",
 848        .type = V4L2_CTRL_TYPE_INTEGER,
 849        .min = 0,
 850        .max = 1,
 851        .step = 1,
 852        .def = 0,
 853};
 854
 855/* subdev file operations */
 856static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = {
 857        .open = ipipeif_init_formats,
 858};
 859
 860/* subdev video operations */
 861static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = {
 862        .s_stream = ipipeif_set_stream,
 863};
 864
 865/* subdev pad operations */
 866static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = {
 867        .enum_mbus_code = ipipeif_enum_mbus_code,
 868        .enum_frame_size = ipipeif_enum_frame_size,
 869        .get_fmt = ipipeif_get_format,
 870        .set_fmt = ipipeif_set_format,
 871};
 872
 873/* subdev operations */
 874static const struct v4l2_subdev_ops ipipeif_v4l2_ops = {
 875        .core = &ipipeif_v4l2_core_ops,
 876        .video = &ipipeif_v4l2_video_ops,
 877        .pad = &ipipeif_v4l2_pad_ops,
 878};
 879
 880static const struct vpfe_video_operations video_in_ops = {
 881        .queue = ipipeif_video_in_queue,
 882};
 883
 884static int
 885ipipeif_link_setup(struct media_entity *entity, const struct media_pad *local,
 886                const struct media_pad *remote, u32 flags)
 887{
 888        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
 889        struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
 890        struct vpfe_device *vpfe = to_vpfe_device(ipipeif);
 891
 892        switch (local->index | media_entity_type(remote->entity)) {
 893        case IPIPEIF_PAD_SINK | MEDIA_ENT_T_DEVNODE:
 894                /* Single shot mode */
 895                if (!(flags & MEDIA_LNK_FL_ENABLED)) {
 896                        ipipeif->input = IPIPEIF_INPUT_NONE;
 897                        break;
 898                }
 899                ipipeif->input = IPIPEIF_INPUT_MEMORY;
 900                break;
 901
 902        case IPIPEIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
 903                /* read from isif */
 904                if (!(flags & MEDIA_LNK_FL_ENABLED)) {
 905                        ipipeif->input = IPIPEIF_INPUT_NONE;
 906                        break;
 907                }
 908                if (ipipeif->input != IPIPEIF_INPUT_NONE)
 909                        return -EBUSY;
 910
 911                ipipeif->input = IPIPEIF_INPUT_ISIF;
 912                break;
 913
 914        case IPIPEIF_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
 915                if (!(flags & MEDIA_LNK_FL_ENABLED)) {
 916                        ipipeif->output = IPIPEIF_OUTPUT_NONE;
 917                        break;
 918                }
 919                if (remote->entity == &vpfe->vpfe_ipipe.subdev.entity)
 920                        /* connencted to ipipe */
 921                        ipipeif->output = IPIPEIF_OUTPUT_IPIPE;
 922                else if (remote->entity == &vpfe->vpfe_resizer.
 923                        crop_resizer.subdev.entity)
 924                        /* connected to resizer */
 925                        ipipeif->output = IPIPEIF_OUTPUT_RESIZER;
 926                else
 927                        return -EINVAL;
 928                break;
 929
 930        default:
 931                return -EINVAL;
 932        }
 933
 934        return 0;
 935}
 936
 937static const struct media_entity_operations ipipeif_media_ops = {
 938        .link_setup = ipipeif_link_setup,
 939};
 940
 941/*
 942 * vpfe_ipipeif_unregister_entities() - Unregister entity
 943 * @ipipeif - pointer to ipipeif subdevice structure.
 944 */
 945void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif)
 946{
 947        /* unregister video device */
 948        vpfe_video_unregister(&ipipeif->video_in);
 949
 950        /* unregister subdev */
 951        v4l2_device_unregister_subdev(&ipipeif->subdev);
 952        /* cleanup entity */
 953        media_entity_cleanup(&ipipeif->subdev.entity);
 954}
 955
 956int
 957vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device *ipipeif,
 958                               struct v4l2_device *vdev)
 959{
 960        struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif);
 961        unsigned int flags;
 962        int ret;
 963
 964        /* Register the subdev */
 965        ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev);
 966        if (ret < 0)
 967                return ret;
 968
 969        ret = vpfe_video_register(&ipipeif->video_in, vdev);
 970        if (ret) {
 971                pr_err("Failed to register ipipeif video-in device\n");
 972                goto fail;
 973        }
 974        ipipeif->video_in.vpfe_dev = vpfe_dev;
 975
 976        flags = 0;
 977        ret = media_entity_create_link(&ipipeif->video_in.video_dev.entity, 0,
 978                                        &ipipeif->subdev.entity, 0, flags);
 979        if (ret < 0)
 980                goto fail;
 981
 982        return 0;
 983fail:
 984        v4l2_device_unregister_subdev(&ipipeif->subdev);
 985
 986        return ret;
 987}
 988
 989#define IPIPEIF_GAIN_HIGH               0x3ff
 990#define IPIPEIF_DEFAULT_GAIN            0x200
 991
 992int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif,
 993                      struct platform_device *pdev)
 994{
 995        struct v4l2_subdev *sd = &ipipeif->subdev;
 996        struct media_pad *pads = &ipipeif->pads[0];
 997        struct media_entity *me = &sd->entity;
 998        static resource_size_t  res_len;
 999        struct resource *res;
1000        int ret;
1001
1002        res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
1003        if (!res)
1004                return -ENOENT;
1005
1006        res_len = resource_size(res);
1007        res = request_mem_region(res->start, res_len, res->name);
1008        if (!res)
1009                return -EBUSY;
1010
1011        ipipeif->ipipeif_base_addr = ioremap_nocache(res->start, res_len);
1012        if (!ipipeif->ipipeif_base_addr) {
1013                ret =  -EBUSY;
1014                goto fail;
1015        }
1016
1017        v4l2_subdev_init(sd, &ipipeif_v4l2_ops);
1018
1019        sd->internal_ops = &ipipeif_v4l2_internal_ops;
1020        strlcpy(sd->name, "DAVINCI IPIPEIF", sizeof(sd->name));
1021        sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1022
1023        v4l2_set_subdevdata(sd, ipipeif);
1024
1025        sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
1026        pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1027        pads[IPIPEIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1028        ipipeif->input = IPIPEIF_INPUT_NONE;
1029        ipipeif->output = IPIPEIF_OUTPUT_NONE;
1030        me->ops = &ipipeif_media_ops;
1031
1032        ret = media_entity_init(me, IPIPEIF_NUM_PADS, pads, 0);
1033        if (ret)
1034                goto fail;
1035
1036        v4l2_ctrl_handler_init(&ipipeif->ctrls, 2);
1037        v4l2_ctrl_new_std(&ipipeif->ctrls, &ipipeif_ctrl_ops,
1038                          V4L2_CID_GAIN, 0,
1039                          IPIPEIF_GAIN_HIGH, 1, IPIPEIF_DEFAULT_GAIN);
1040        v4l2_ctrl_new_custom(&ipipeif->ctrls, &vpfe_ipipeif_dpcm_pred, NULL);
1041        v4l2_ctrl_handler_setup(&ipipeif->ctrls);
1042        sd->ctrl_handler = &ipipeif->ctrls;
1043
1044        ipipeif->video_in.ops = &video_in_ops;
1045        ipipeif->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1046        ret = vpfe_video_init(&ipipeif->video_in, "IPIPEIF");
1047        if (ret) {
1048                pr_err("Failed to init IPIPEIF video-in device\n");
1049                goto fail;
1050        }
1051        ipipeif_set_default_config(ipipeif);
1052        return 0;
1053fail:
1054        release_mem_region(res->start, res_len);
1055        return ret;
1056}
1057
1058void
1059vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif,
1060                     struct platform_device *pdev)
1061{
1062        struct resource *res;
1063
1064        v4l2_ctrl_handler_free(&ipipeif->ctrls);
1065        iounmap(ipipeif->ipipeif_base_addr);
1066        res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
1067        if (res)
1068                release_mem_region(res->start, resource_size(res));
1069
1070}
1071