linux/drivers/staging/media/atomisp/pci/atomisp_subdev.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Support for Medifield PNW Camera Imaging ISP subsystem.
   4 *
   5 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License version
   9 * 2 as published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 *
  17 */
  18#include <linux/module.h>
  19#include <linux/uaccess.h>
  20#include <linux/delay.h>
  21#include <linux/device.h>
  22#include <linux/mm.h>
  23#include <linux/sched.h>
  24#include <linux/slab.h>
  25
  26#include <media/v4l2-event.h>
  27#include <media/v4l2-mediabus.h>
  28#include "atomisp_cmd.h"
  29#include "atomisp_common.h"
  30#include "atomisp_compat.h"
  31#include "atomisp_internal.h"
  32
  33const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = {
  34        { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_BGGR },
  35        { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_GBRG },
  36        { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_GRBG },
  37        { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_RGGB },
  38        { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_BGGR },
  39        { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_GBRG },
  40        { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_GRBG },
  41        { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_RGGB },
  42        { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_BGGR },
  43        { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_GBRG },
  44        { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_GRBG },
  45        { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_RGGB },
  46        { MEDIA_BUS_FMT_UYVY8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0 },
  47        { MEDIA_BUS_FMT_YUYV8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0 },
  48#if 0 // disabled due to clang warnings
  49        { MEDIA_BUS_FMT_JPEG_1X8, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 },
  50        { V4L2_MBUS_FMT_CUSTOM_NV12, 12, 12, IA_CSS_FRAME_FORMAT_NV12, 0 },
  51        { V4L2_MBUS_FMT_CUSTOM_NV21, 12, 12, IA_CSS_FRAME_FORMAT_NV21, 0 },
  52#endif
  53        { V4L2_MBUS_FMT_CUSTOM_YUV420, 12, 12, ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY, 0 },
  54#if 0
  55        { V4L2_MBUS_FMT_CUSTOM_M10MO_RAW, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 },
  56#endif
  57        /* no valid V4L2 MBUS code for metadata format, so leave it 0. */
  58        { 0, 0, 0, ATOMISP_INPUT_FORMAT_EMBEDDED, 0 },
  59        {}
  60};
  61
  62static const struct {
  63        u32 code;
  64        u32 compressed;
  65} compressed_codes[] = {
  66        { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 },
  67        { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 },
  68        { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 },
  69        { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 },
  70};
  71
  72u32 atomisp_subdev_uncompressed_code(u32 code)
  73{
  74        unsigned int i;
  75
  76        for (i = 0; i < ARRAY_SIZE(compressed_codes); i++)
  77                if (code == compressed_codes[i].compressed)
  78                        return compressed_codes[i].code;
  79
  80        return code;
  81}
  82
  83bool atomisp_subdev_is_compressed(u32 code)
  84{
  85        int i;
  86
  87        for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
  88                if (code == atomisp_in_fmt_conv[i].code)
  89                        return atomisp_in_fmt_conv[i].bpp !=
  90                               atomisp_in_fmt_conv[i].depth;
  91
  92        return false;
  93}
  94
  95const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv(u32 code)
  96{
  97        int i;
  98
  99        for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
 100                if (code == atomisp_in_fmt_conv[i].code)
 101                        return atomisp_in_fmt_conv + i;
 102
 103        return NULL;
 104}
 105
 106const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
 107    enum atomisp_input_format atomisp_in_fmt)
 108{
 109        int i;
 110
 111        for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++)
 112                if (atomisp_in_fmt_conv[i].atomisp_in_fmt == atomisp_in_fmt)
 113                        return atomisp_in_fmt_conv + i;
 114
 115        return NULL;
 116}
 117
 118bool atomisp_subdev_format_conversion(struct atomisp_sub_device *asd,
 119                                      unsigned int source_pad)
 120{
 121        struct v4l2_mbus_framefmt *sink, *src;
 122
 123        sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
 124                                       V4L2_SUBDEV_FORMAT_ACTIVE,
 125                                       ATOMISP_SUBDEV_PAD_SINK);
 126        src = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
 127                                      V4L2_SUBDEV_FORMAT_ACTIVE, source_pad);
 128
 129        return atomisp_is_mbuscode_raw(sink->code)
 130               && !atomisp_is_mbuscode_raw(src->code);
 131}
 132
 133uint16_t atomisp_subdev_source_pad(struct video_device *vdev)
 134{
 135        struct media_link *link;
 136        u16 ret = 0;
 137
 138        list_for_each_entry(link, &vdev->entity.links, list) {
 139                if (link->source) {
 140                        ret = link->source->index;
 141                        break;
 142                }
 143        }
 144        return ret;
 145}
 146
 147/*
 148 * V4L2 subdev operations
 149 */
 150
 151/*
 152 * isp_subdev_ioctl - CCDC module private ioctl's
 153 * @sd: ISP V4L2 subdevice
 154 * @cmd: ioctl command
 155 * @arg: ioctl argument
 156 *
 157 * Return 0 on success or a negative error code otherwise.
 158 */
 159static long isp_subdev_ioctl(struct v4l2_subdev *sd,
 160                             unsigned int cmd, void *arg)
 161{
 162        return 0;
 163}
 164
 165/*
 166 * isp_subdev_set_power - Power on/off the CCDC module
 167 * @sd: ISP V4L2 subdevice
 168 * @on: power on/off
 169 *
 170 * Return 0 on success or a negative error code otherwise.
 171 */
 172static int isp_subdev_set_power(struct v4l2_subdev *sd, int on)
 173{
 174        return 0;
 175}
 176
 177static int isp_subdev_subscribe_event(struct v4l2_subdev *sd,
 178                                      struct v4l2_fh *fh,
 179                                      struct v4l2_event_subscription *sub)
 180{
 181        struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
 182        struct atomisp_device *isp = isp_sd->isp;
 183
 184        if (sub->type != V4L2_EVENT_FRAME_SYNC &&
 185            sub->type != V4L2_EVENT_FRAME_END &&
 186            sub->type != V4L2_EVENT_ATOMISP_3A_STATS_READY &&
 187            sub->type != V4L2_EVENT_ATOMISP_METADATA_READY &&
 188            sub->type != V4L2_EVENT_ATOMISP_PAUSE_BUFFER &&
 189            sub->type != V4L2_EVENT_ATOMISP_CSS_RESET &&
 190            sub->type != V4L2_EVENT_ATOMISP_RAW_BUFFERS_ALLOC_DONE &&
 191            sub->type != V4L2_EVENT_ATOMISP_ACC_COMPLETE)
 192                return -EINVAL;
 193
 194        if (sub->type == V4L2_EVENT_FRAME_SYNC &&
 195            !atomisp_css_valid_sof(isp))
 196                return -EINVAL;
 197
 198        return v4l2_event_subscribe(fh, sub, 16, NULL);
 199}
 200
 201static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd,
 202                                        struct v4l2_fh *fh,
 203                                        struct v4l2_event_subscription *sub)
 204{
 205        return v4l2_event_unsubscribe(fh, sub);
 206}
 207
 208/*
 209 * isp_subdev_enum_mbus_code - Handle pixel format enumeration
 210 * @sd: pointer to v4l2 subdev structure
 211 * @fh : V4L2 subdev file handle
 212 * @code: pointer to v4l2_subdev_pad_mbus_code_enum structure
 213 * return -EINVAL or zero on success
 214 */
 215static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd,
 216                                     struct v4l2_subdev_pad_config *cfg,
 217                                     struct v4l2_subdev_mbus_code_enum *code)
 218{
 219        if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1)
 220                return -EINVAL;
 221
 222        code->code = atomisp_in_fmt_conv[code->index].code;
 223
 224        return 0;
 225}
 226
 227static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad,
 228                                    uint32_t target)
 229{
 230        switch (pad) {
 231        case ATOMISP_SUBDEV_PAD_SINK:
 232                switch (target) {
 233                case V4L2_SEL_TGT_CROP:
 234                        return 0;
 235                }
 236                break;
 237        default:
 238                switch (target) {
 239                case V4L2_SEL_TGT_COMPOSE:
 240                        return 0;
 241                }
 242                break;
 243        }
 244
 245        return -EINVAL;
 246}
 247
 248struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
 249        struct v4l2_subdev_pad_config *cfg,
 250        u32 which, uint32_t pad,
 251        uint32_t target)
 252{
 253        struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
 254
 255        if (which == V4L2_SUBDEV_FORMAT_TRY) {
 256                switch (target) {
 257                case V4L2_SEL_TGT_CROP:
 258                        return v4l2_subdev_get_try_crop(sd, cfg, pad);
 259                case V4L2_SEL_TGT_COMPOSE:
 260                        return v4l2_subdev_get_try_compose(sd, cfg, pad);
 261                }
 262        }
 263
 264        switch (target) {
 265        case V4L2_SEL_TGT_CROP:
 266                return &isp_sd->fmt[pad].crop;
 267        case V4L2_SEL_TGT_COMPOSE:
 268                return &isp_sd->fmt[pad].compose;
 269        }
 270
 271        return NULL;
 272}
 273
 274struct v4l2_mbus_framefmt
 275*atomisp_subdev_get_ffmt(struct v4l2_subdev *sd,
 276                         struct v4l2_subdev_pad_config *cfg, uint32_t which,
 277                         uint32_t pad)
 278{
 279        struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
 280
 281        if (which == V4L2_SUBDEV_FORMAT_TRY)
 282                return v4l2_subdev_get_try_format(sd, cfg, pad);
 283
 284        return &isp_sd->fmt[pad].fmt;
 285}
 286
 287static void isp_get_fmt_rect(struct v4l2_subdev *sd,
 288                             struct v4l2_subdev_pad_config *cfg, uint32_t which,
 289                             struct v4l2_mbus_framefmt **ffmt,
 290                             struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
 291                             struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM])
 292{
 293        unsigned int i;
 294
 295        for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) {
 296                ffmt[i] = atomisp_subdev_get_ffmt(sd, cfg, which, i);
 297                crop[i] = atomisp_subdev_get_rect(sd, cfg, which, i,
 298                                                  V4L2_SEL_TGT_CROP);
 299                comp[i] = atomisp_subdev_get_rect(sd, cfg, which, i,
 300                                                  V4L2_SEL_TGT_COMPOSE);
 301        }
 302}
 303
 304static void isp_subdev_propagate(struct v4l2_subdev *sd,
 305                                 struct v4l2_subdev_pad_config *cfg,
 306                                 u32 which, uint32_t pad, uint32_t target,
 307                                 uint32_t flags)
 308{
 309        struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
 310        struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
 311                       *comp[ATOMISP_SUBDEV_PADS_NUM];
 312
 313        if (flags & V4L2_SEL_FLAG_KEEP_CONFIG)
 314                return;
 315
 316        isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp);
 317
 318        switch (pad) {
 319        case ATOMISP_SUBDEV_PAD_SINK: {
 320                struct v4l2_rect r = {0};
 321
 322                /* Only crop target supported on sink pad. */
 323                r.width = ffmt[pad]->width;
 324                r.height = ffmt[pad]->height;
 325
 326                atomisp_subdev_set_selection(sd, cfg, which, pad,
 327                                             target, flags, &r);
 328                break;
 329        }
 330        }
 331}
 332
 333static int isp_subdev_get_selection(struct v4l2_subdev *sd,
 334                                    struct v4l2_subdev_pad_config *cfg,
 335                                    struct v4l2_subdev_selection *sel)
 336{
 337        struct v4l2_rect *rec;
 338        int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
 339
 340        if (rval)
 341                return rval;
 342
 343        rec = atomisp_subdev_get_rect(sd, cfg, sel->which, sel->pad,
 344                                      sel->target);
 345        if (!rec)
 346                return -EINVAL;
 347
 348        sel->r = *rec;
 349        return 0;
 350}
 351
 352static char *atomisp_pad_str[] = { "ATOMISP_SUBDEV_PAD_SINK",
 353                                   "ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE",
 354                                   "ATOMISP_SUBDEV_PAD_SOURCE_VF",
 355                                   "ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW",
 356                                   "ATOMISP_SUBDEV_PAD_SOURCE_VIDEO"
 357                                 };
 358
 359int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
 360                                 struct v4l2_subdev_pad_config *cfg,
 361                                 u32 which, uint32_t pad, uint32_t target,
 362                                 u32 flags, struct v4l2_rect *r)
 363{
 364        struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
 365        struct atomisp_device *isp = isp_sd->isp;
 366        struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM];
 367        u16 vdev_pad = atomisp_subdev_source_pad(sd->devnode);
 368        struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
 369                       *comp[ATOMISP_SUBDEV_PADS_NUM];
 370        enum atomisp_input_stream_id stream_id;
 371        unsigned int i;
 372        unsigned int padding_w = pad_w;
 373        unsigned int padding_h = pad_h;
 374
 375        stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad);
 376
 377        isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp);
 378
 379        dev_dbg(isp->dev,
 380                "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n",
 381                atomisp_pad_str[pad], target == V4L2_SEL_TGT_CROP
 382                ? "V4L2_SEL_TGT_CROP" : "V4L2_SEL_TGT_COMPOSE",
 383                r->left, r->top, r->width, r->height,
 384                which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
 385                : "V4L2_SUBDEV_FORMAT_ACTIVE", flags);
 386
 387        r->width = rounddown(r->width, ATOM_ISP_STEP_WIDTH);
 388        r->height = rounddown(r->height, ATOM_ISP_STEP_HEIGHT);
 389
 390        switch (pad) {
 391        case ATOMISP_SUBDEV_PAD_SINK: {
 392                /* Only crop target supported on sink pad. */
 393                unsigned int dvs_w, dvs_h;
 394
 395                crop[pad]->width = ffmt[pad]->width;
 396                crop[pad]->height = ffmt[pad]->height;
 397
 398                /* Workaround for BYT 1080p perfectshot since the maxinum resolution of
 399                 * front camera ov2722 is 1932x1092 and cannot use pad_w > 12*/
 400                if (!strncmp(isp->inputs[isp_sd->input_curr].camera->name,
 401                             "ov2722", 6) && crop[pad]->height == 1092) {
 402                        padding_w = 12;
 403                        padding_h = 12;
 404                }
 405
 406                if (isp->inputs[isp_sd->input_curr].type == SOC_CAMERA) {
 407                        padding_w = 0;
 408                        padding_h = 0;
 409                }
 410
 411                if (atomisp_subdev_format_conversion(isp_sd,
 412                                                     isp_sd->capture_pad)
 413                    && crop[pad]->width && crop[pad]->height)
 414                        crop[pad]->width -= padding_w, crop[pad]->height -= padding_h;
 415
 416                /* if subdev type is SOC camera,we do not need to set DVS */
 417                if (isp->inputs[isp_sd->input_curr].type == SOC_CAMERA)
 418                        isp_sd->params.video_dis_en = 0;
 419
 420                if (isp_sd->params.video_dis_en &&
 421                    isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
 422                    !isp_sd->continuous_mode->val) {
 423                        /* This resolution contains 20 % of DVS slack
 424                         * (of the desired captured image before
 425                         * scaling, or 1 / 6 of what we get from the
 426                         * sensor) in both width and height. Remove
 427                         * it. */
 428                        crop[pad]->width = roundup(crop[pad]->width * 5 / 6,
 429                                                   ATOM_ISP_STEP_WIDTH);
 430                        crop[pad]->height = roundup(crop[pad]->height * 5 / 6,
 431                                                    ATOM_ISP_STEP_HEIGHT);
 432                }
 433
 434                crop[pad]->width = min(crop[pad]->width, r->width);
 435                crop[pad]->height = min(crop[pad]->height, r->height);
 436
 437                if (!(flags & V4L2_SEL_FLAG_KEEP_CONFIG)) {
 438                        for (i = ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE;
 439                             i < ATOMISP_SUBDEV_PADS_NUM; i++) {
 440                                struct v4l2_rect tmp = *crop[pad];
 441
 442                                atomisp_subdev_set_selection(
 443                                    sd, cfg, which, i, V4L2_SEL_TGT_COMPOSE,
 444                                    flags, &tmp);
 445                        }
 446                }
 447
 448                if (which == V4L2_SUBDEV_FORMAT_TRY)
 449                        break;
 450
 451                if (isp_sd->params.video_dis_en &&
 452                    isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
 453                    !isp_sd->continuous_mode->val) {
 454                        dvs_w = rounddown(crop[pad]->width / 5,
 455                                          ATOM_ISP_STEP_WIDTH);
 456                        dvs_h = rounddown(crop[pad]->height / 5,
 457                                          ATOM_ISP_STEP_HEIGHT);
 458                } else if (!isp_sd->params.video_dis_en &&
 459                           isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
 460                        /*
 461                         * For CSS2.0, digital zoom needs to set dvs envelope to 12
 462                         * when dvs is disabled.
 463                         */
 464                        dvs_w = dvs_h = 12;
 465                } else
 466                        dvs_w = dvs_h = 0;
 467
 468                atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h);
 469                atomisp_css_input_set_effective_resolution(isp_sd, stream_id,
 470                        crop[pad]->width, crop[pad]->height);
 471
 472                break;
 473        }
 474        case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
 475        case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: {
 476                /* Only compose target is supported on source pads. */
 477
 478                if (isp_sd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
 479                        /* Scaling is disabled in this mode */
 480                        r->width = crop[ATOMISP_SUBDEV_PAD_SINK]->width;
 481                        r->height = crop[ATOMISP_SUBDEV_PAD_SINK]->height;
 482                }
 483
 484                if (crop[ATOMISP_SUBDEV_PAD_SINK]->width == r->width
 485                    && crop[ATOMISP_SUBDEV_PAD_SINK]->height == r->height)
 486                        isp_sd->params.yuv_ds_en = false;
 487                else
 488                        isp_sd->params.yuv_ds_en = true;
 489
 490                comp[pad]->width = r->width;
 491                comp[pad]->height = r->height;
 492
 493                if (r->width == 0 || r->height == 0 ||
 494                    crop[ATOMISP_SUBDEV_PAD_SINK]->width == 0 ||
 495                    crop[ATOMISP_SUBDEV_PAD_SINK]->height == 0)
 496                        break;
 497                /*
 498                 * do cropping on sensor input if ratio of required resolution
 499                 * is different with sensor output resolution ratio:
 500                 *
 501                 * ratio = width / height
 502                 *
 503                 * if ratio_output < ratio_sensor:
 504                 *      effect_width = sensor_height * out_width / out_height;
 505                 *      effect_height = sensor_height;
 506                 * else
 507                 *      effect_width = sensor_width;
 508                 *      effect_height = sensor_width * out_height / out_width;
 509                 *
 510                 */
 511                if (r->width * crop[ATOMISP_SUBDEV_PAD_SINK]->height <
 512                    crop[ATOMISP_SUBDEV_PAD_SINK]->width * r->height)
 513                        atomisp_css_input_set_effective_resolution(isp_sd,
 514                                stream_id,
 515                                rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
 516                                          height * r->width / r->height,
 517                                          ATOM_ISP_STEP_WIDTH),
 518                                crop[ATOMISP_SUBDEV_PAD_SINK]->height);
 519                else
 520                        atomisp_css_input_set_effective_resolution(isp_sd,
 521                                stream_id,
 522                                crop[ATOMISP_SUBDEV_PAD_SINK]->width,
 523                                rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]->
 524                                          width * r->height / r->width,
 525                                          ATOM_ISP_STEP_WIDTH));
 526
 527                break;
 528        }
 529        case ATOMISP_SUBDEV_PAD_SOURCE_VF:
 530        case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
 531                comp[pad]->width = r->width;
 532                comp[pad]->height = r->height;
 533                break;
 534        default:
 535                return -EINVAL;
 536        }
 537
 538        /* Set format dimensions on non-sink pads as well. */
 539        if (pad != ATOMISP_SUBDEV_PAD_SINK) {
 540                ffmt[pad]->width = comp[pad]->width;
 541                ffmt[pad]->height = comp[pad]->height;
 542        }
 543
 544        if (!atomisp_subdev_get_rect(sd, cfg, which, pad, target))
 545                return -EINVAL;
 546        *r = *atomisp_subdev_get_rect(sd, cfg, which, pad, target);
 547
 548        dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n",
 549                r->left, r->top, r->width, r->height);
 550
 551        return 0;
 552}
 553
 554static int isp_subdev_set_selection(struct v4l2_subdev *sd,
 555                                    struct v4l2_subdev_pad_config *cfg,
 556                                    struct v4l2_subdev_selection *sel)
 557{
 558        int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
 559
 560        if (rval)
 561                return rval;
 562
 563        return atomisp_subdev_set_selection(sd, cfg, sel->which, sel->pad,
 564                                            sel->target, sel->flags, &sel->r);
 565}
 566
 567static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd)
 568{
 569        struct v4l2_control ctrl = {0};
 570        struct atomisp_device *isp = asd->isp;
 571        int hbin, vbin;
 572        int ret;
 573
 574        if (isp->inputs[asd->input_curr].type == FILE_INPUT ||
 575            isp->inputs[asd->input_curr].type == TEST_PATTERN)
 576                return 0;
 577
 578        ctrl.id = V4L2_CID_BIN_FACTOR_HORZ;
 579        ret =
 580            v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler,
 581                        &ctrl);
 582        hbin = ctrl.value;
 583        ctrl.id = V4L2_CID_BIN_FACTOR_VERT;
 584        ret |=
 585            v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler,
 586                        &ctrl);
 587        vbin = ctrl.value;
 588
 589        /*
 590         * ISP needs to know binning factor from sensor.
 591         * In case horizontal and vertical sensor's binning factors
 592         * are different or sensor does not support binning factor CID,
 593         * ISP will apply default 0 value.
 594         */
 595        if (ret || hbin != vbin)
 596                hbin = 0;
 597
 598        return hbin;
 599}
 600
 601void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
 602                             struct v4l2_subdev_pad_config *cfg, uint32_t which,
 603                             u32 pad, struct v4l2_mbus_framefmt *ffmt)
 604{
 605        struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
 606        struct atomisp_device *isp = isp_sd->isp;
 607        struct v4l2_mbus_framefmt *__ffmt =
 608            atomisp_subdev_get_ffmt(sd, cfg, which, pad);
 609        u16 vdev_pad = atomisp_subdev_source_pad(sd->devnode);
 610        enum atomisp_input_stream_id stream_id;
 611
 612        dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n",
 613                atomisp_pad_str[pad], ffmt->width, ffmt->height, ffmt->code,
 614                which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY"
 615                : "V4L2_SUBDEV_FORMAT_ACTIVE");
 616
 617        stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad);
 618
 619        switch (pad) {
 620        case ATOMISP_SUBDEV_PAD_SINK: {
 621                const struct atomisp_in_fmt_conv *fc =
 622                    atomisp_find_in_fmt_conv(ffmt->code);
 623
 624                if (!fc) {
 625                        fc = atomisp_in_fmt_conv;
 626                        ffmt->code = fc->code;
 627                        dev_dbg(isp->dev, "using 0x%8.8x instead\n",
 628                                ffmt->code);
 629                }
 630
 631                *__ffmt = *ffmt;
 632
 633                isp_subdev_propagate(sd, cfg, which, pad,
 634                                     V4L2_SEL_TGT_CROP, 0);
 635
 636                if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
 637                        atomisp_css_input_set_resolution(isp_sd,
 638                                                         stream_id, ffmt);
 639                        atomisp_css_input_set_binning_factor(isp_sd,
 640                                                             stream_id,
 641                                                             atomisp_get_sensor_bin_factor(isp_sd));
 642                        atomisp_css_input_set_bayer_order(isp_sd, stream_id,
 643                                                          fc->bayer_order);
 644                        atomisp_css_input_set_format(isp_sd, stream_id,
 645                                                     fc->atomisp_in_fmt);
 646                        atomisp_css_set_default_isys_config(isp_sd, stream_id,
 647                                                            ffmt);
 648                }
 649
 650                break;
 651        }
 652        case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
 653        case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
 654        case ATOMISP_SUBDEV_PAD_SOURCE_VF:
 655        case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO:
 656                __ffmt->code = ffmt->code;
 657                break;
 658        }
 659}
 660
 661/*
 662 * isp_subdev_get_format - Retrieve the video format on a pad
 663 * @sd : ISP V4L2 subdevice
 664 * @fh : V4L2 subdev file handle
 665 * @pad: Pad number
 666 * @fmt: Format
 667 *
 668 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
 669 * to the format type.
 670 */
 671static int isp_subdev_get_format(struct v4l2_subdev *sd,
 672                                 struct v4l2_subdev_pad_config *cfg,
 673                                 struct v4l2_subdev_format *fmt)
 674{
 675        fmt->format = *atomisp_subdev_get_ffmt(sd, cfg, fmt->which, fmt->pad);
 676
 677        return 0;
 678}
 679
 680/*
 681 * isp_subdev_set_format - Set the video format on a pad
 682 * @sd : ISP subdev V4L2 subdevice
 683 * @fh : V4L2 subdev file handle
 684 * @pad: Pad number
 685 * @fmt: Format
 686 *
 687 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
 688 * to the format type.
 689 */
 690static int isp_subdev_set_format(struct v4l2_subdev *sd,
 691                                 struct v4l2_subdev_pad_config *cfg,
 692                                 struct v4l2_subdev_format *fmt)
 693{
 694        atomisp_subdev_set_ffmt(sd, cfg, fmt->which, fmt->pad, &fmt->format);
 695
 696        return 0;
 697}
 698
 699/* V4L2 subdev core operations */
 700static const struct v4l2_subdev_core_ops isp_subdev_v4l2_core_ops = {
 701        .ioctl = isp_subdev_ioctl, .s_power = isp_subdev_set_power,
 702        .subscribe_event = isp_subdev_subscribe_event,
 703        .unsubscribe_event = isp_subdev_unsubscribe_event,
 704};
 705
 706/* V4L2 subdev pad operations */
 707static const struct v4l2_subdev_pad_ops isp_subdev_v4l2_pad_ops = {
 708        .enum_mbus_code = isp_subdev_enum_mbus_code,
 709        .get_fmt = isp_subdev_get_format,
 710        .set_fmt = isp_subdev_set_format,
 711        .get_selection = isp_subdev_get_selection,
 712        .set_selection = isp_subdev_set_selection,
 713        .link_validate = v4l2_subdev_link_validate_default,
 714};
 715
 716/* V4L2 subdev operations */
 717static const struct v4l2_subdev_ops isp_subdev_v4l2_ops = {
 718        .core = &isp_subdev_v4l2_core_ops,
 719        .pad = &isp_subdev_v4l2_pad_ops,
 720};
 721
 722static void isp_subdev_init_params(struct atomisp_sub_device *asd)
 723{
 724        unsigned int i;
 725
 726        /* parameters initialization */
 727        INIT_LIST_HEAD(&asd->s3a_stats);
 728        INIT_LIST_HEAD(&asd->s3a_stats_in_css);
 729        INIT_LIST_HEAD(&asd->s3a_stats_ready);
 730        INIT_LIST_HEAD(&asd->dis_stats);
 731        INIT_LIST_HEAD(&asd->dis_stats_in_css);
 732        spin_lock_init(&asd->dis_stats_lock);
 733        for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
 734                INIT_LIST_HEAD(&asd->metadata[i]);
 735                INIT_LIST_HEAD(&asd->metadata_in_css[i]);
 736                INIT_LIST_HEAD(&asd->metadata_ready[i]);
 737        }
 738}
 739
 740/*
 741* isp_subdev_link_setup - Setup isp subdev connections
 742* @entity: ispsubdev media entity
 743* @local: Pad at the local end of the link
 744* @remote: Pad at the remote end of the link
 745* @flags: Link flags
 746*
 747* return -EINVAL or zero on success
 748*/
 749static int isp_subdev_link_setup(struct media_entity *entity,
 750                                 const struct media_pad *local,
 751                                 const struct media_pad *remote, u32 flags)
 752{
 753        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
 754        struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
 755        struct atomisp_device *isp = isp_sd->isp;
 756        unsigned int i;
 757
 758        switch (local->index | is_media_entity_v4l2_subdev(remote->entity)) {
 759        case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
 760                /* Read from the sensor CSI2-ports. */
 761                if (!(flags & MEDIA_LNK_FL_ENABLED)) {
 762                        isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
 763                        break;
 764                }
 765
 766                if (isp_sd->input != ATOMISP_SUBDEV_INPUT_NONE)
 767                        return -EBUSY;
 768
 769                for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
 770                        if (remote->entity != &isp->csi2_port[i].subdev.entity)
 771                                continue;
 772
 773                        isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_PORT1 + i;
 774                        return 0;
 775                }
 776
 777                return -EINVAL;
 778
 779        case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_OLD_BASE:
 780                /* read from memory */
 781                if (flags & MEDIA_LNK_FL_ENABLED) {
 782                        if (isp_sd->input >= ATOMISP_SUBDEV_INPUT_CSI2_PORT1 &&
 783                            isp_sd->input < (ATOMISP_SUBDEV_INPUT_CSI2_PORT1
 784                                             + ATOMISP_CAMERA_NR_PORTS))
 785                                return -EBUSY;
 786                        isp_sd->input = ATOMISP_SUBDEV_INPUT_MEMORY;
 787                } else {
 788                        if (isp_sd->input == ATOMISP_SUBDEV_INPUT_MEMORY)
 789                                isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
 790                }
 791                break;
 792
 793        case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW | MEDIA_ENT_F_OLD_BASE:
 794                /* always write to memory */
 795                break;
 796
 797        case ATOMISP_SUBDEV_PAD_SOURCE_VF | MEDIA_ENT_F_OLD_BASE:
 798                /* always write to memory */
 799                break;
 800
 801        case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE | MEDIA_ENT_F_OLD_BASE:
 802                /* always write to memory */
 803                break;
 804
 805        case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO | MEDIA_ENT_F_OLD_BASE:
 806                /* always write to memory */
 807                break;
 808
 809        default:
 810                return -EINVAL;
 811        }
 812
 813        return 0;
 814}
 815
 816/* media operations */
 817static const struct media_entity_operations isp_subdev_media_ops = {
 818        .link_setup = isp_subdev_link_setup,
 819        .link_validate = v4l2_subdev_link_validate,
 820        /*       .set_power = v4l2_subdev_set_power,    */
 821};
 822
 823static int __atomisp_update_run_mode(struct atomisp_sub_device *asd)
 824{
 825        struct atomisp_device *isp = asd->isp;
 826        struct v4l2_ctrl *ctrl = asd->run_mode;
 827        struct v4l2_ctrl *c;
 828        s32 mode;
 829
 830        if (ctrl->val != ATOMISP_RUN_MODE_VIDEO &&
 831            asd->continuous_mode->val)
 832                mode = ATOMISP_RUN_MODE_PREVIEW;
 833        else
 834                mode = ctrl->val;
 835
 836        c = v4l2_ctrl_find(
 837                isp->inputs[asd->input_curr].camera->ctrl_handler,
 838                V4L2_CID_RUN_MODE);
 839
 840        if (c)
 841                return v4l2_ctrl_s_ctrl(c, mode);
 842
 843        return 0;
 844}
 845
 846int atomisp_update_run_mode(struct atomisp_sub_device *asd)
 847{
 848        int rval;
 849
 850        mutex_lock(asd->ctrl_handler.lock);
 851        rval = __atomisp_update_run_mode(asd);
 852        mutex_unlock(asd->ctrl_handler.lock);
 853
 854        return rval;
 855}
 856
 857static int s_ctrl(struct v4l2_ctrl *ctrl)
 858{
 859        struct atomisp_sub_device *asd = container_of(
 860                                             ctrl->handler, struct atomisp_sub_device, ctrl_handler);
 861
 862        switch (ctrl->id) {
 863        case V4L2_CID_RUN_MODE:
 864                return __atomisp_update_run_mode(asd);
 865        case V4L2_CID_DEPTH_MODE:
 866                if (asd->streaming != ATOMISP_DEVICE_STREAMING_DISABLED) {
 867                        dev_err(asd->isp->dev,
 868                                "ISP is streaming, it is not supported to change the depth mode\n");
 869                        return -EINVAL;
 870                }
 871                break;
 872        }
 873
 874        return 0;
 875}
 876
 877static const struct v4l2_ctrl_ops ctrl_ops = {
 878        .s_ctrl = &s_ctrl,
 879};
 880
 881static const struct v4l2_ctrl_config ctrl_fmt_auto = {
 882        .ops = &ctrl_ops,
 883        .id = V4L2_CID_FMT_AUTO,
 884        .name = "Automatic format guessing",
 885        .type = V4L2_CTRL_TYPE_BOOLEAN,
 886        .min = 0,
 887        .max = 1,
 888        .step = 1,
 889        .def = 1,
 890};
 891
 892static const char *const ctrl_run_mode_menu[] = {
 893        NULL,
 894        "Video",
 895        "Still capture",
 896        "Continuous capture",
 897        "Preview",
 898};
 899
 900static const struct v4l2_ctrl_config ctrl_run_mode = {
 901        .ops = &ctrl_ops,
 902        .id = V4L2_CID_RUN_MODE,
 903        .name = "Atomisp run mode",
 904        .type = V4L2_CTRL_TYPE_MENU,
 905        .min = 1,
 906        .def = 1,
 907        .max = 4,
 908        .qmenu = ctrl_run_mode_menu,
 909};
 910
 911static const char *const ctrl_vfpp_mode_menu[] = {
 912        "Enable",                       /* vfpp always enabled */
 913        "Disable to scaler mode",       /* CSS into video mode and disable */
 914        "Disable to low latency mode",  /* CSS into still mode and disable */
 915};
 916
 917static const struct v4l2_ctrl_config ctrl_vfpp = {
 918        .id = V4L2_CID_VFPP,
 919        .name = "Atomisp vf postprocess",
 920        .type = V4L2_CTRL_TYPE_MENU,
 921        .min = 0,
 922        .def = 0,
 923        .max = 2,
 924        .qmenu = ctrl_vfpp_mode_menu,
 925};
 926
 927/*
 928 * Control for ISP continuous mode
 929 *
 930 * When enabled, capture processing is possible without
 931 * stopping the preview pipeline. When disabled, ISP needs
 932 * to be restarted between preview and capture.
 933 */
 934static const struct v4l2_ctrl_config ctrl_continuous_mode = {
 935        .ops = &ctrl_ops,
 936        .id = V4L2_CID_ATOMISP_CONTINUOUS_MODE,
 937        .type = V4L2_CTRL_TYPE_BOOLEAN,
 938        .name = "Continuous mode",
 939        .min = 0,
 940        .max = 1,
 941        .step = 1,
 942        .def = 0,
 943};
 944
 945/*
 946 * Control for continuous mode raw buffer size
 947 *
 948 * The size of the RAW ringbuffer sets limit on how much
 949 * back in time application can go when requesting capture
 950 * frames to be rendered, and how many frames can be rendered
 951 * in a burst at full sensor rate.
 952 *
 953 * Note: this setting has a big impact on memory consumption of
 954 * the CSS subsystem.
 955 */
 956static const struct v4l2_ctrl_config ctrl_continuous_raw_buffer_size = {
 957        .ops = &ctrl_ops,
 958        .id = V4L2_CID_ATOMISP_CONTINUOUS_RAW_BUFFER_SIZE,
 959        .type = V4L2_CTRL_TYPE_INTEGER,
 960        .name = "Continuous raw ringbuffer size",
 961        .min = 1,
 962        .max = 100, /* depends on CSS version, runtime checked */
 963        .step = 1,
 964        .def = 3,
 965};
 966
 967/*
 968 * Control for enabling continuous viewfinder
 969 *
 970 * When enabled, and ISP is in continuous mode (see ctrl_continuous_mode ),
 971 * preview pipeline continues concurrently with capture
 972 * processing. When disabled, and continuous mode is used,
 973 * preview is paused while captures are processed, but
 974 * full pipeline restart is not needed.
 975 *
 976 * By setting this to disabled, capture processing is
 977 * essentially given priority over preview, and the effective
 978 * capture output rate may be higher than with continuous
 979 * viewfinder enabled.
 980 */
 981static const struct v4l2_ctrl_config ctrl_continuous_viewfinder = {
 982        .id = V4L2_CID_ATOMISP_CONTINUOUS_VIEWFINDER,
 983        .type = V4L2_CTRL_TYPE_BOOLEAN,
 984        .name = "Continuous viewfinder",
 985        .min = 0,
 986        .max = 1,
 987        .step = 1,
 988        .def = 0,
 989};
 990
 991/*
 992 * Control for enabling Lock&Unlock Raw Buffer mechanism
 993 *
 994 * When enabled, Raw Buffer can be locked and unlocked.
 995 * Application can hold the exp_id of Raw Buffer
 996 * and unlock it when no longer needed.
 997 * Note: Make sure set this configuration before creating stream.
 998 */
 999static const struct v4l2_ctrl_config ctrl_enable_raw_buffer_lock = {
1000        .id = V4L2_CID_ENABLE_RAW_BUFFER_LOCK,
1001        .type = V4L2_CTRL_TYPE_BOOLEAN,
1002        .name = "Lock Unlock Raw Buffer",
1003        .min = 0,
1004        .max = 1,
1005        .step = 1,
1006        .def = 0,
1007};
1008
1009/*
1010 * Control to disable digital zoom of the whole stream
1011 *
1012 * When it is true, pipe configuration enable_dz will be set to false.
1013 * This can help get a better performance by disabling pp binary.
1014 *
1015 * Note: Make sure set this configuration before creating stream.
1016 */
1017static const struct v4l2_ctrl_config ctrl_disable_dz = {
1018        .id = V4L2_CID_DISABLE_DZ,
1019        .type = V4L2_CTRL_TYPE_BOOLEAN,
1020        .name = "Disable digital zoom",
1021        .min = 0,
1022        .max = 1,
1023        .step = 1,
1024        .def = 0,
1025};
1026
1027/*
1028 * Control for ISP depth mode
1029 *
1030 * When enabled, that means ISP will deal with dual streams and sensors will be
1031 * in slave/master mode.
1032 * slave sensor will have no output until master sensor is streamed on.
1033 */
1034static const struct v4l2_ctrl_config ctrl_depth_mode = {
1035        .ops = &ctrl_ops,
1036        .id = V4L2_CID_DEPTH_MODE,
1037        .type = V4L2_CTRL_TYPE_BOOLEAN,
1038        .name = "Depth mode",
1039        .min = 0,
1040        .max = 1,
1041        .step = 1,
1042        .def = 0,
1043};
1044
1045/*
1046 * Control for selectting ISP version
1047 *
1048 * When enabled, that means ISP version will be used ISP2.7. when disable, the
1049 * isp will default to use ISP2.2.
1050 * Note: Make sure set this configuration before creating stream.
1051 */
1052static const struct v4l2_ctrl_config ctrl_select_isp_version = {
1053        .ops = &ctrl_ops,
1054        .id = V4L2_CID_ATOMISP_SELECT_ISP_VERSION,
1055        .type = V4L2_CTRL_TYPE_BOOLEAN,
1056        .name = "Select Isp version",
1057        .min = 0,
1058        .max = 1,
1059        .step = 1,
1060        .def = 0,
1061};
1062
1063#if 0 /* #ifdef CONFIG_ION */
1064/*
1065 * Control for ISP ion device fd
1066 *
1067 * userspace will open ion device and pass the fd to kernel.
1068 * this fd will be used to map shared fd to buffer.
1069 */
1070/* V4L2_CID_ATOMISP_ION_DEVICE_FD is not defined */
1071static const struct v4l2_ctrl_config ctrl_ion_dev_fd = {
1072        .ops = &ctrl_ops,
1073        .id = V4L2_CID_ATOMISP_ION_DEVICE_FD,
1074        .type = V4L2_CTRL_TYPE_INTEGER,
1075        .name = "Ion Device Fd",
1076        .min = -1,
1077        .max = 1024,
1078        .step = 1,
1079        .def = ION_FD_UNSET
1080};
1081#endif
1082
1083static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
1084                                     struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type)
1085{
1086        pipe->type = buf_type;
1087        pipe->asd = asd;
1088        pipe->isp = asd->isp;
1089        spin_lock_init(&pipe->irq_lock);
1090        INIT_LIST_HEAD(&pipe->activeq);
1091        INIT_LIST_HEAD(&pipe->activeq_out);
1092        INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
1093        INIT_LIST_HEAD(&pipe->per_frame_params);
1094        memset(pipe->frame_request_config_id,
1095               0, VIDEO_MAX_FRAME * sizeof(unsigned int));
1096        memset(pipe->frame_params,
1097               0, VIDEO_MAX_FRAME *
1098               sizeof(struct atomisp_css_params_with_list *));
1099}
1100
1101static void atomisp_init_acc_pipe(struct atomisp_sub_device *asd,
1102                                  struct atomisp_acc_pipe *pipe)
1103{
1104        pipe->asd = asd;
1105        pipe->isp = asd->isp;
1106        INIT_LIST_HEAD(&asd->acc.fw);
1107        INIT_LIST_HEAD(&asd->acc.memory_maps);
1108        ida_init(&asd->acc.ida);
1109}
1110
1111/*
1112 * isp_subdev_init_entities - Initialize V4L2 subdev and media entity
1113 * @asd: ISP CCDC module
1114 *
1115 * Return 0 on success and a negative error code on failure.
1116 */
1117static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
1118{
1119        struct v4l2_subdev *sd = &asd->subdev;
1120        struct media_pad *pads = asd->pads;
1121        struct media_entity *me = &sd->entity;
1122        int ret;
1123
1124        asd->input = ATOMISP_SUBDEV_INPUT_NONE;
1125
1126        v4l2_subdev_init(sd, &isp_subdev_v4l2_ops);
1127        sprintf(sd->name, "ATOMISP_SUBDEV_%d", asd->index);
1128        v4l2_set_subdevdata(sd, asd);
1129        sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
1130
1131        pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1132        pads[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].flags = MEDIA_PAD_FL_SOURCE;
1133        pads[ATOMISP_SUBDEV_PAD_SOURCE_VF].flags = MEDIA_PAD_FL_SOURCE;
1134        pads[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].flags = MEDIA_PAD_FL_SOURCE;
1135        pads[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE;
1136
1137        asd->fmt[ATOMISP_SUBDEV_PAD_SINK].fmt.code =
1138            MEDIA_BUS_FMT_SBGGR10_1X10;
1139        asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW].fmt.code =
1140            MEDIA_BUS_FMT_SBGGR10_1X10;
1141        asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VF].fmt.code =
1142            MEDIA_BUS_FMT_SBGGR10_1X10;
1143        asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE].fmt.code =
1144            MEDIA_BUS_FMT_SBGGR10_1X10;
1145        asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE_VIDEO].fmt.code =
1146            MEDIA_BUS_FMT_SBGGR10_1X10;
1147
1148        me->ops = &isp_subdev_media_ops;
1149        me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
1150        ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads);
1151        if (ret < 0)
1152                return ret;
1153
1154        atomisp_init_subdev_pipe(asd, &asd->video_in,
1155                                 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1156
1157        atomisp_init_subdev_pipe(asd, &asd->video_out_preview,
1158                                 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1159
1160        atomisp_init_subdev_pipe(asd, &asd->video_out_vf,
1161                                 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1162
1163        atomisp_init_subdev_pipe(asd, &asd->video_out_capture,
1164                                 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1165
1166        atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture,
1167                                 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1168
1169        atomisp_init_acc_pipe(asd, &asd->video_acc);
1170
1171        ret = atomisp_video_init(&asd->video_in, "MEMORY");
1172        if (ret < 0)
1173                return ret;
1174
1175        ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE");
1176        if (ret < 0)
1177                return ret;
1178
1179        ret = atomisp_video_init(&asd->video_out_vf, "VIEWFINDER");
1180        if (ret < 0)
1181                return ret;
1182
1183        ret = atomisp_video_init(&asd->video_out_preview, "PREVIEW");
1184        if (ret < 0)
1185                return ret;
1186
1187        ret = atomisp_video_init(&asd->video_out_video_capture, "VIDEO");
1188        if (ret < 0)
1189                return ret;
1190
1191        atomisp_acc_init(&asd->video_acc, "ACC");
1192
1193        ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, 1);
1194        if (ret)
1195                return ret;
1196
1197        asd->fmt_auto = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1198                                             &ctrl_fmt_auto, NULL);
1199        asd->run_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1200                                             &ctrl_run_mode, NULL);
1201        asd->vfpp = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1202                                         &ctrl_vfpp, NULL);
1203        asd->continuous_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1204                               &ctrl_continuous_mode, NULL);
1205        asd->continuous_viewfinder = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1206                                     &ctrl_continuous_viewfinder,
1207                                     NULL);
1208        asd->continuous_raw_buffer_size =
1209            v4l2_ctrl_new_custom(&asd->ctrl_handler,
1210                                 &ctrl_continuous_raw_buffer_size,
1211                                 NULL);
1212
1213        asd->enable_raw_buffer_lock =
1214            v4l2_ctrl_new_custom(&asd->ctrl_handler,
1215                                 &ctrl_enable_raw_buffer_lock,
1216                                 NULL);
1217        asd->depth_mode =
1218            v4l2_ctrl_new_custom(&asd->ctrl_handler,
1219                                 &ctrl_depth_mode,
1220                                 NULL);
1221        asd->disable_dz =
1222            v4l2_ctrl_new_custom(&asd->ctrl_handler,
1223                                 &ctrl_disable_dz,
1224                                 NULL);
1225        if (IS_ISP2401) {
1226                asd->select_isp_version = v4l2_ctrl_new_custom(&asd->ctrl_handler,
1227                                                               &ctrl_select_isp_version,
1228                                                               NULL);
1229        }
1230
1231        /* Make controls visible on subdev as well. */
1232        asd->subdev.ctrl_handler = &asd->ctrl_handler;
1233        spin_lock_init(&asd->raw_buffer_bitmap_lock);
1234        return asd->ctrl_handler.error;
1235}
1236
1237int atomisp_create_pads_links(struct atomisp_device *isp)
1238{
1239        struct atomisp_sub_device *asd;
1240        int i, j, ret = 0;
1241
1242        isp->num_of_streams = 2;
1243        for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
1244                for (j = 0; j < isp->num_of_streams; j++) {
1245                        ret =
1246                            media_create_pad_link(&isp->csi2_port[i].subdev.
1247                                                  entity, CSI2_PAD_SOURCE,
1248                                                  &isp->asd[j].subdev.entity,
1249                                                  ATOMISP_SUBDEV_PAD_SINK, 0);
1250                        if (ret < 0)
1251                                return ret;
1252                }
1253        }
1254        for (i = 0; i < isp->input_cnt - 2; i++) {
1255                ret = media_create_pad_link(&isp->inputs[i].camera->entity, 0,
1256                                            &isp->csi2_port[isp->inputs[i].
1257                                                    port].subdev.entity,
1258                                            CSI2_PAD_SINK,
1259                                            MEDIA_LNK_FL_ENABLED |
1260                                            MEDIA_LNK_FL_IMMUTABLE);
1261                if (ret < 0)
1262                        return ret;
1263        }
1264        for (i = 0; i < isp->num_of_streams; i++) {
1265                asd = &isp->asd[i];
1266                ret = media_create_pad_link(&asd->subdev.entity,
1267                                            ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW,
1268                                            &asd->video_out_preview.vdev.entity,
1269                                            0, 0);
1270                if (ret < 0)
1271                        return ret;
1272                ret = media_create_pad_link(&asd->subdev.entity,
1273                                            ATOMISP_SUBDEV_PAD_SOURCE_VF,
1274                                            &asd->video_out_vf.vdev.entity, 0,
1275                                            0);
1276                if (ret < 0)
1277                        return ret;
1278                ret = media_create_pad_link(&asd->subdev.entity,
1279                                            ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE,
1280                                            &asd->video_out_capture.vdev.entity,
1281                                            0, 0);
1282                if (ret < 0)
1283                        return ret;
1284                ret = media_create_pad_link(&asd->subdev.entity,
1285                                            ATOMISP_SUBDEV_PAD_SOURCE_VIDEO,
1286                                            &asd->video_out_video_capture.vdev.
1287                                            entity, 0, 0);
1288                if (ret < 0)
1289                        return ret;
1290                /*
1291                 * file input only supported on subdev0
1292                 * so do not create pad link for subdevs other then subdev0
1293                 */
1294                if (asd->index)
1295                        return 0;
1296                ret = media_create_pad_link(&asd->video_in.vdev.entity,
1297                                            0, &asd->subdev.entity,
1298                                            ATOMISP_SUBDEV_PAD_SINK, 0);
1299                if (ret < 0)
1300                        return ret;
1301        }
1302        return 0;
1303}
1304
1305static void atomisp_subdev_cleanup_entities(struct atomisp_sub_device *asd)
1306{
1307        v4l2_ctrl_handler_free(&asd->ctrl_handler);
1308
1309        media_entity_cleanup(&asd->subdev.entity);
1310}
1311
1312void atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device *asd)
1313{
1314        struct v4l2_fh *fh, *fh_tmp;
1315        struct v4l2_event event;
1316        unsigned int i, pending_event;
1317
1318        list_for_each_entry_safe(fh, fh_tmp,
1319                                 &asd->subdev.devnode->fh_list, list) {
1320                pending_event = v4l2_event_pending(fh);
1321                for (i = 0; i < pending_event; i++)
1322                        v4l2_event_dequeue(fh, &event, 1);
1323        }
1324}
1325
1326void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd)
1327{
1328        atomisp_subdev_cleanup_entities(asd);
1329        v4l2_device_unregister_subdev(&asd->subdev);
1330        atomisp_video_unregister(&asd->video_in);
1331        atomisp_video_unregister(&asd->video_out_preview);
1332        atomisp_video_unregister(&asd->video_out_vf);
1333        atomisp_video_unregister(&asd->video_out_capture);
1334        atomisp_video_unregister(&asd->video_out_video_capture);
1335        atomisp_acc_unregister(&asd->video_acc);
1336}
1337
1338int atomisp_subdev_register_entities(struct atomisp_sub_device *asd,
1339                                     struct v4l2_device *vdev)
1340{
1341        int ret;
1342        u32 device_caps;
1343
1344        /*
1345         * FIXME: check if all device caps are properly initialized.
1346         * Should any of those use V4L2_CAP_META_OUTPUT? Probably yes.
1347         */
1348
1349        device_caps = V4L2_CAP_VIDEO_CAPTURE |
1350                      V4L2_CAP_STREAMING;
1351
1352        /* Register the subdev and video node. */
1353
1354        ret = v4l2_device_register_subdev(vdev, &asd->subdev);
1355        if (ret < 0)
1356                goto error;
1357
1358        asd->video_out_capture.vdev.v4l2_dev = vdev;
1359        asd->video_out_capture.vdev.device_caps = device_caps |
1360                                                  V4L2_CAP_VIDEO_OUTPUT;
1361        ret = video_register_device(&asd->video_out_capture.vdev,
1362                                    VFL_TYPE_VIDEO, -1);
1363        if (ret < 0)
1364                goto error;
1365
1366        asd->video_out_vf.vdev.v4l2_dev = vdev;
1367        asd->video_out_vf.vdev.device_caps = device_caps |
1368                                             V4L2_CAP_VIDEO_OUTPUT;
1369        ret = video_register_device(&asd->video_out_vf.vdev,
1370                                    VFL_TYPE_VIDEO, -1);
1371        if (ret < 0)
1372                goto error;
1373        asd->video_out_preview.vdev.v4l2_dev = vdev;
1374        asd->video_out_preview.vdev.device_caps = device_caps |
1375                                                  V4L2_CAP_VIDEO_OUTPUT;
1376        ret = video_register_device(&asd->video_out_preview.vdev,
1377                                    VFL_TYPE_VIDEO, -1);
1378        if (ret < 0)
1379                goto error;
1380        asd->video_out_video_capture.vdev.v4l2_dev = vdev;
1381        asd->video_out_video_capture.vdev.device_caps = device_caps |
1382                                                        V4L2_CAP_VIDEO_OUTPUT;
1383        ret = video_register_device(&asd->video_out_video_capture.vdev,
1384                                    VFL_TYPE_VIDEO, -1);
1385        if (ret < 0)
1386                goto error;
1387        asd->video_acc.vdev.v4l2_dev = vdev;
1388        asd->video_acc.vdev.device_caps = device_caps |
1389                                          V4L2_CAP_VIDEO_OUTPUT;
1390        ret = video_register_device(&asd->video_acc.vdev,
1391                                    VFL_TYPE_VIDEO, -1);
1392        if (ret < 0)
1393                goto error;
1394
1395        /*
1396         * file input only supported on subdev0
1397         * so do not create video node for subdevs other then subdev0
1398         */
1399        if (asd->index)
1400                return 0;
1401
1402        asd->video_in.vdev.v4l2_dev = vdev;
1403        asd->video_in.vdev.device_caps = device_caps |
1404                                          V4L2_CAP_VIDEO_CAPTURE;
1405        ret = video_register_device(&asd->video_in.vdev,
1406                                    VFL_TYPE_VIDEO, -1);
1407        if (ret < 0)
1408                goto error;
1409
1410        return 0;
1411
1412error:
1413        atomisp_subdev_unregister_entities(asd);
1414        return ret;
1415}
1416
1417/*
1418 * atomisp_subdev_init - ISP Subdevice  initialization.
1419 * @dev: Device pointer specific to the ATOM ISP.
1420 *
1421 * TODO: Get the initialisation values from platform data.
1422 *
1423 * Return 0 on success or a negative error code otherwise.
1424 */
1425int atomisp_subdev_init(struct atomisp_device *isp)
1426{
1427        struct atomisp_sub_device *asd;
1428        int i, ret = 0;
1429
1430        /*
1431         * CSS2.0 running ISP2400 support
1432         * multiple streams
1433         */
1434        isp->num_of_streams = 2;
1435        isp->asd = devm_kzalloc(isp->dev, sizeof(struct atomisp_sub_device) *
1436                                isp->num_of_streams, GFP_KERNEL);
1437        if (!isp->asd)
1438                return -ENOMEM;
1439        for (i = 0; i < isp->num_of_streams; i++) {
1440                asd = &isp->asd[i];
1441                spin_lock_init(&asd->lock);
1442                asd->isp = isp;
1443                isp_subdev_init_params(asd);
1444                asd->index = i;
1445                ret = isp_subdev_init_entities(asd);
1446                if (ret < 0) {
1447                        atomisp_subdev_cleanup_entities(asd);
1448                        break;
1449                }
1450        }
1451
1452        return ret;
1453}
1454