linux/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Support for Clovertrail PNW Camera Imaging ISP subsystem.
   4 *
   5 * Copyright (c) 2013 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
  19#include <media/videobuf-vmalloc.h>
  20#include <media/v4l2-dev.h>
  21#include <media/v4l2-event.h>
  22
  23#include "mmu/isp_mmu.h"
  24#include "mmu/sh_mmu_mrfld.h"
  25#include "hmm/hmm_bo.h"
  26#include "hmm/hmm.h"
  27
  28#include "atomisp_compat.h"
  29#include "atomisp_internal.h"
  30#include "atomisp_cmd.h"
  31#include "atomisp-regs.h"
  32#include "atomisp_fops.h"
  33#include "atomisp_ioctl.h"
  34#include "atomisp_acc.h"
  35
  36#include "ia_css_debug.h"
  37#include "ia_css_isp_param.h"
  38#include "sh_css_hrt.h"
  39#include "ia_css_isys.h"
  40
  41#include <linux/io.h>
  42#include <linux/pm_runtime.h>
  43
  44/* Assume max number of ACC stages */
  45#define MAX_ACC_STAGES  20
  46
  47/* Ideally, this should come from CSS headers */
  48#define NO_LINK -1
  49
  50/*
  51 * to serialize MMIO access , this is due to ISP2400 silicon issue Sighting
  52 * #4684168, if concurrency access happened, system may hard hang.
  53 */
  54static DEFINE_SPINLOCK(mmio_lock);
  55
  56enum frame_info_type {
  57        ATOMISP_CSS_VF_FRAME,
  58        ATOMISP_CSS_SECOND_VF_FRAME,
  59        ATOMISP_CSS_OUTPUT_FRAME,
  60        ATOMISP_CSS_SECOND_OUTPUT_FRAME,
  61        ATOMISP_CSS_RAW_FRAME,
  62};
  63
  64struct bayer_ds_factor {
  65        unsigned int numerator;
  66        unsigned int denominator;
  67};
  68
  69static void atomisp_css2_hw_store_8(hrt_address addr, uint8_t data)
  70{
  71        struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
  72        unsigned long flags;
  73
  74        spin_lock_irqsave(&mmio_lock, flags);
  75        writeb(data, isp->base + (addr & 0x003FFFFF));
  76        spin_unlock_irqrestore(&mmio_lock, flags);
  77}
  78
  79static void atomisp_css2_hw_store_16(hrt_address addr, uint16_t data)
  80{
  81        struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
  82        unsigned long flags;
  83
  84        spin_lock_irqsave(&mmio_lock, flags);
  85        writew(data, isp->base + (addr & 0x003FFFFF));
  86        spin_unlock_irqrestore(&mmio_lock, flags);
  87}
  88
  89void atomisp_css2_hw_store_32(hrt_address addr, uint32_t data)
  90{
  91        struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
  92        unsigned long flags;
  93
  94        spin_lock_irqsave(&mmio_lock, flags);
  95        writel(data, isp->base + (addr & 0x003FFFFF));
  96        spin_unlock_irqrestore(&mmio_lock, flags);
  97}
  98
  99static uint8_t atomisp_css2_hw_load_8(hrt_address addr)
 100{
 101        struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
 102        unsigned long flags;
 103        u8 ret;
 104
 105        spin_lock_irqsave(&mmio_lock, flags);
 106        ret = readb(isp->base + (addr & 0x003FFFFF));
 107        spin_unlock_irqrestore(&mmio_lock, flags);
 108        return ret;
 109}
 110
 111static uint16_t atomisp_css2_hw_load_16(hrt_address addr)
 112{
 113        struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
 114        unsigned long flags;
 115        u16 ret;
 116
 117        spin_lock_irqsave(&mmio_lock, flags);
 118        ret = readw(isp->base + (addr & 0x003FFFFF));
 119        spin_unlock_irqrestore(&mmio_lock, flags);
 120        return ret;
 121}
 122
 123static uint32_t atomisp_css2_hw_load_32(hrt_address addr)
 124{
 125        struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
 126        unsigned long flags;
 127        u32 ret;
 128
 129        spin_lock_irqsave(&mmio_lock, flags);
 130        ret = readl(isp->base + (addr & 0x003FFFFF));
 131        spin_unlock_irqrestore(&mmio_lock, flags);
 132        return ret;
 133}
 134
 135static void atomisp_css2_hw_store(hrt_address addr, const void *from, uint32_t n)
 136{
 137        struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
 138        unsigned long flags;
 139        unsigned int i;
 140
 141        addr &= 0x003FFFFF;
 142        spin_lock_irqsave(&mmio_lock, flags);
 143        for (i = 0; i < n; i++, from++)
 144                writeb(*(s8 *)from, isp->base + addr + i);
 145
 146        spin_unlock_irqrestore(&mmio_lock, flags);
 147}
 148
 149static void atomisp_css2_hw_load(hrt_address addr, void *to, uint32_t n)
 150{
 151        struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
 152        unsigned long flags;
 153        unsigned int i;
 154
 155        addr &= 0x003FFFFF;
 156        spin_lock_irqsave(&mmio_lock, flags);
 157        for (i = 0; i < n; i++, to++)
 158                *(s8 *)to = readb(isp->base + addr + i);
 159        spin_unlock_irqrestore(&mmio_lock, flags);
 160}
 161
 162static int  __printf(1, 0) atomisp_css2_dbg_ftrace_print(const char *fmt,
 163                                                         va_list args)
 164{
 165        ftrace_vprintk(fmt, args);
 166        return 0;
 167}
 168
 169static int  __printf(1, 0) atomisp_vprintk(const char *fmt, va_list args)
 170{
 171        vprintk(fmt, args);
 172        return 0;
 173}
 174
 175void atomisp_load_uint32(hrt_address addr, uint32_t *data)
 176{
 177        *data = atomisp_css2_hw_load_32(addr);
 178}
 179
 180static int hmm_get_mmu_base_addr(struct device *dev, unsigned int *mmu_base_addr)
 181{
 182        if (!sh_mmu_mrfld.get_pd_base) {
 183                dev_err(dev, "get mmu base address failed.\n");
 184                return -EINVAL;
 185        }
 186
 187        *mmu_base_addr = sh_mmu_mrfld.get_pd_base(&bo_device.mmu,
 188                         bo_device.mmu.base_address);
 189        return 0;
 190}
 191
 192static void __dump_pipe_config(struct atomisp_sub_device *asd,
 193                               struct atomisp_stream_env *stream_env,
 194                               unsigned int pipe_id)
 195{
 196        struct atomisp_device *isp = asd->isp;
 197
 198        if (stream_env->pipes[pipe_id]) {
 199                struct ia_css_pipe_config *p_config;
 200                struct ia_css_pipe_extra_config *pe_config;
 201
 202                p_config = &stream_env->pipe_configs[pipe_id];
 203                pe_config = &stream_env->pipe_extra_configs[pipe_id];
 204                dev_dbg(isp->dev, "dumping pipe[%d] config:\n", pipe_id);
 205                dev_dbg(isp->dev,
 206                        "pipe_config.pipe_mode:%d.\n", p_config->mode);
 207                dev_dbg(isp->dev,
 208                        "pipe_config.output_info[0] w=%d, h=%d.\n",
 209                        p_config->output_info[0].res.width,
 210                        p_config->output_info[0].res.height);
 211                dev_dbg(isp->dev,
 212                        "pipe_config.vf_pp_in_res w=%d, h=%d.\n",
 213                        p_config->vf_pp_in_res.width,
 214                        p_config->vf_pp_in_res.height);
 215                dev_dbg(isp->dev,
 216                        "pipe_config.capt_pp_in_res w=%d, h=%d.\n",
 217                        p_config->capt_pp_in_res.width,
 218                        p_config->capt_pp_in_res.height);
 219                dev_dbg(isp->dev,
 220                        "pipe_config.output.padded w=%d.\n",
 221                        p_config->output_info[0].padded_width);
 222                dev_dbg(isp->dev,
 223                        "pipe_config.vf_output_info[0] w=%d, h=%d.\n",
 224                        p_config->vf_output_info[0].res.width,
 225                        p_config->vf_output_info[0].res.height);
 226                dev_dbg(isp->dev,
 227                        "pipe_config.bayer_ds_out_res w=%d, h=%d.\n",
 228                        p_config->bayer_ds_out_res.width,
 229                        p_config->bayer_ds_out_res.height);
 230                dev_dbg(isp->dev,
 231                        "pipe_config.envelope w=%d, h=%d.\n",
 232                        p_config->dvs_envelope.width,
 233                        p_config->dvs_envelope.height);
 234                dev_dbg(isp->dev,
 235                        "pipe_config.dvs_frame_delay=%d.\n",
 236                        p_config->dvs_frame_delay);
 237                dev_dbg(isp->dev,
 238                        "pipe_config.isp_pipe_version:%d.\n",
 239                        p_config->isp_pipe_version);
 240                dev_dbg(isp->dev,
 241                        "pipe_config.acc_extension=%p.\n",
 242                        p_config->acc_extension);
 243                dev_dbg(isp->dev,
 244                        "pipe_config.acc_stages=%p.\n",
 245                        p_config->acc_stages);
 246                dev_dbg(isp->dev,
 247                        "pipe_config.num_acc_stages=%d.\n",
 248                        p_config->num_acc_stages);
 249                dev_dbg(isp->dev,
 250                        "pipe_config.acc_num_execs=%d.\n",
 251                        p_config->acc_num_execs);
 252                dev_dbg(isp->dev,
 253                        "pipe_config.default_capture_config.capture_mode=%d.\n",
 254                        p_config->default_capture_config.mode);
 255                dev_dbg(isp->dev,
 256                        "pipe_config.enable_dz=%d.\n",
 257                        p_config->enable_dz);
 258                dev_dbg(isp->dev,
 259                        "pipe_config.default_capture_config.enable_xnr=%d.\n",
 260                        p_config->default_capture_config.enable_xnr);
 261                dev_dbg(isp->dev,
 262                        "dumping pipe[%d] extra config:\n", pipe_id);
 263                dev_dbg(isp->dev,
 264                        "pipe_extra_config.enable_raw_binning:%d.\n",
 265                        pe_config->enable_raw_binning);
 266                dev_dbg(isp->dev,
 267                        "pipe_extra_config.enable_yuv_ds:%d.\n",
 268                        pe_config->enable_yuv_ds);
 269                dev_dbg(isp->dev,
 270                        "pipe_extra_config.enable_high_speed:%d.\n",
 271                        pe_config->enable_high_speed);
 272                dev_dbg(isp->dev,
 273                        "pipe_extra_config.enable_dvs_6axis:%d.\n",
 274                        pe_config->enable_dvs_6axis);
 275                dev_dbg(isp->dev,
 276                        "pipe_extra_config.enable_reduced_pipe:%d.\n",
 277                        pe_config->enable_reduced_pipe);
 278                dev_dbg(isp->dev,
 279                        "pipe_(extra_)config.enable_dz:%d.\n",
 280                        p_config->enable_dz);
 281                dev_dbg(isp->dev,
 282                        "pipe_extra_config.disable_vf_pp:%d.\n",
 283                        pe_config->disable_vf_pp);
 284        }
 285}
 286
 287static void __dump_stream_config(struct atomisp_sub_device *asd,
 288                                 struct atomisp_stream_env *stream_env)
 289{
 290        struct atomisp_device *isp = asd->isp;
 291        struct ia_css_stream_config *s_config;
 292        int j;
 293        bool valid_stream = false;
 294
 295        for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) {
 296                if (stream_env->pipes[j]) {
 297                        __dump_pipe_config(asd, stream_env, j);
 298                        valid_stream = true;
 299                }
 300        }
 301        if (!valid_stream)
 302                return;
 303        s_config = &stream_env->stream_config;
 304        dev_dbg(isp->dev, "stream_config.mode=%d.\n", s_config->mode);
 305
 306        if (s_config->mode == IA_CSS_INPUT_MODE_SENSOR ||
 307            s_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
 308                dev_dbg(isp->dev, "stream_config.source.port.port=%d.\n",
 309                        s_config->source.port.port);
 310                dev_dbg(isp->dev, "stream_config.source.port.num_lanes=%d.\n",
 311                        s_config->source.port.num_lanes);
 312                dev_dbg(isp->dev, "stream_config.source.port.timeout=%d.\n",
 313                        s_config->source.port.timeout);
 314                dev_dbg(isp->dev, "stream_config.source.port.rxcount=0x%x.\n",
 315                        s_config->source.port.rxcount);
 316                dev_dbg(isp->dev, "stream_config.source.port.compression.type=%d.\n",
 317                        s_config->source.port.compression.type);
 318                dev_dbg(isp->dev,
 319                        "stream_config.source.port.compression.compressed_bits_per_pixel=%d.\n",
 320                        s_config->source.port.compression.
 321                        compressed_bits_per_pixel);
 322                dev_dbg(isp->dev,
 323                        "stream_config.source.port.compression.uncompressed_bits_per_pixel=%d.\n",
 324                        s_config->source.port.compression.
 325                        uncompressed_bits_per_pixel);
 326        } else if (s_config->mode == IA_CSS_INPUT_MODE_TPG) {
 327                dev_dbg(isp->dev, "stream_config.source.tpg.id=%d.\n",
 328                        s_config->source.tpg.id);
 329                dev_dbg(isp->dev, "stream_config.source.tpg.mode=%d.\n",
 330                        s_config->source.tpg.mode);
 331                dev_dbg(isp->dev, "stream_config.source.tpg.x_mask=%d.\n",
 332                        s_config->source.tpg.x_mask);
 333                dev_dbg(isp->dev, "stream_config.source.tpg.x_delta=%d.\n",
 334                        s_config->source.tpg.x_delta);
 335                dev_dbg(isp->dev, "stream_config.source.tpg.y_mask=%d.\n",
 336                        s_config->source.tpg.y_mask);
 337                dev_dbg(isp->dev, "stream_config.source.tpg.y_delta=%d.\n",
 338                        s_config->source.tpg.y_delta);
 339                dev_dbg(isp->dev, "stream_config.source.tpg.xy_mask=%d.\n",
 340                        s_config->source.tpg.xy_mask);
 341        } else if (s_config->mode == IA_CSS_INPUT_MODE_PRBS) {
 342                dev_dbg(isp->dev, "stream_config.source.prbs.id=%d.\n",
 343                        s_config->source.prbs.id);
 344                dev_dbg(isp->dev, "stream_config.source.prbs.h_blank=%d.\n",
 345                        s_config->source.prbs.h_blank);
 346                dev_dbg(isp->dev, "stream_config.source.prbs.v_blank=%d.\n",
 347                        s_config->source.prbs.v_blank);
 348                dev_dbg(isp->dev, "stream_config.source.prbs.seed=%d.\n",
 349                        s_config->source.prbs.seed);
 350                dev_dbg(isp->dev, "stream_config.source.prbs.seed1=%d.\n",
 351                        s_config->source.prbs.seed1);
 352        }
 353
 354        for (j = 0; j < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; j++) {
 355                dev_dbg(isp->dev, "stream_configisys_config[%d].input_res w=%d, h=%d.\n",
 356                        j,
 357                        s_config->isys_config[j].input_res.width,
 358                        s_config->isys_config[j].input_res.height);
 359
 360                dev_dbg(isp->dev, "stream_configisys_config[%d].linked_isys_stream_id=%d\n",
 361                        j,
 362                        s_config->isys_config[j].linked_isys_stream_id);
 363
 364                dev_dbg(isp->dev, "stream_configisys_config[%d].format=%d\n",
 365                        j,
 366                        s_config->isys_config[j].format);
 367
 368                dev_dbg(isp->dev, "stream_configisys_config[%d].valid=%d.\n",
 369                        j,
 370                        s_config->isys_config[j].valid);
 371        }
 372
 373        dev_dbg(isp->dev, "stream_config.input_config.input_res w=%d, h=%d.\n",
 374                s_config->input_config.input_res.width,
 375                s_config->input_config.input_res.height);
 376
 377        dev_dbg(isp->dev, "stream_config.input_config.effective_res w=%d, h=%d.\n",
 378                s_config->input_config.effective_res.width,
 379                s_config->input_config.effective_res.height);
 380
 381        dev_dbg(isp->dev, "stream_config.input_config.format=%d\n",
 382                s_config->input_config.format);
 383
 384        dev_dbg(isp->dev, "stream_config.input_config.bayer_order=%d.\n",
 385                s_config->input_config.bayer_order);
 386
 387        dev_dbg(isp->dev, "stream_config.pixels_per_clock=%d.\n",
 388                s_config->pixels_per_clock);
 389        dev_dbg(isp->dev, "stream_config.online=%d.\n", s_config->online);
 390        dev_dbg(isp->dev, "stream_config.continuous=%d.\n",
 391                s_config->continuous);
 392        dev_dbg(isp->dev, "stream_config.disable_cont_viewfinder=%d.\n",
 393                s_config->disable_cont_viewfinder);
 394        dev_dbg(isp->dev, "stream_config.channel_id=%d.\n",
 395                s_config->channel_id);
 396        dev_dbg(isp->dev, "stream_config.init_num_cont_raw_buf=%d.\n",
 397                s_config->init_num_cont_raw_buf);
 398        dev_dbg(isp->dev, "stream_config.target_num_cont_raw_buf=%d.\n",
 399                s_config->target_num_cont_raw_buf);
 400        dev_dbg(isp->dev, "stream_config.left_padding=%d.\n",
 401                s_config->left_padding);
 402        dev_dbg(isp->dev, "stream_config.sensor_binning_factor=%d.\n",
 403                s_config->sensor_binning_factor);
 404        dev_dbg(isp->dev, "stream_config.pixels_per_clock=%d.\n",
 405                s_config->pixels_per_clock);
 406        dev_dbg(isp->dev, "stream_config.pack_raw_pixels=%d.\n",
 407                s_config->pack_raw_pixels);
 408        dev_dbg(isp->dev, "stream_config.flash_gpio_pin=%d.\n",
 409                s_config->flash_gpio_pin);
 410        dev_dbg(isp->dev, "stream_config.mipi_buffer_config.size_mem_words=%d.\n",
 411                s_config->mipi_buffer_config.size_mem_words);
 412        dev_dbg(isp->dev, "stream_config.mipi_buffer_config.contiguous=%d.\n",
 413                s_config->mipi_buffer_config.contiguous);
 414        dev_dbg(isp->dev, "stream_config.metadata_config.data_type=%d.\n",
 415                s_config->metadata_config.data_type);
 416        dev_dbg(isp->dev, "stream_config.metadata_config.resolution w=%d, h=%d.\n",
 417                s_config->metadata_config.resolution.width,
 418                s_config->metadata_config.resolution.height);
 419}
 420
 421static int __destroy_stream(struct atomisp_sub_device *asd,
 422                            struct atomisp_stream_env *stream_env, bool force)
 423{
 424        struct atomisp_device *isp = asd->isp;
 425        int i;
 426        unsigned long timeout;
 427
 428        if (!stream_env->stream)
 429                return 0;
 430
 431        if (!force) {
 432                for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
 433                        if (stream_env->update_pipe[i])
 434                                break;
 435
 436                if (i == IA_CSS_PIPE_ID_NUM)
 437                        return 0;
 438        }
 439
 440        if (stream_env->stream_state == CSS_STREAM_STARTED
 441            && ia_css_stream_stop(stream_env->stream) != 0) {
 442                dev_err(isp->dev, "stop stream failed.\n");
 443                return -EINVAL;
 444        }
 445
 446        if (stream_env->stream_state == CSS_STREAM_STARTED) {
 447                timeout = jiffies + msecs_to_jiffies(40);
 448                while (1) {
 449                        if (ia_css_stream_has_stopped(stream_env->stream))
 450                                break;
 451
 452                        if (time_after(jiffies, timeout)) {
 453                                dev_warn(isp->dev, "stop stream timeout.\n");
 454                                break;
 455                        }
 456
 457                        usleep_range(100, 200);
 458                }
 459        }
 460
 461        stream_env->stream_state = CSS_STREAM_STOPPED;
 462
 463        if (ia_css_stream_destroy(stream_env->stream)) {
 464                dev_err(isp->dev, "destroy stream failed.\n");
 465                return -EINVAL;
 466        }
 467        stream_env->stream_state = CSS_STREAM_UNINIT;
 468        stream_env->stream = NULL;
 469
 470        return 0;
 471}
 472
 473static int __destroy_streams(struct atomisp_sub_device *asd, bool force)
 474{
 475        int ret, i;
 476
 477        for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
 478                ret = __destroy_stream(asd, &asd->stream_env[i], force);
 479                if (ret)
 480                        return ret;
 481        }
 482        asd->stream_prepared = false;
 483        return 0;
 484}
 485
 486static int __create_stream(struct atomisp_sub_device *asd,
 487                           struct atomisp_stream_env *stream_env)
 488{
 489        int pipe_index = 0, i;
 490        struct ia_css_pipe *multi_pipes[IA_CSS_PIPE_ID_NUM];
 491
 492        for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) {
 493                if (stream_env->pipes[i])
 494                        multi_pipes[pipe_index++] = stream_env->pipes[i];
 495        }
 496        if (pipe_index == 0)
 497                return 0;
 498
 499        stream_env->stream_config.target_num_cont_raw_buf =
 500            asd->continuous_raw_buffer_size->val;
 501        stream_env->stream_config.channel_id = stream_env->ch_id;
 502        stream_env->stream_config.ia_css_enable_raw_buffer_locking =
 503            asd->enable_raw_buffer_lock->val;
 504
 505        __dump_stream_config(asd, stream_env);
 506        if (ia_css_stream_create(&stream_env->stream_config,
 507                                 pipe_index, multi_pipes, &stream_env->stream) != 0)
 508                return -EINVAL;
 509        if (ia_css_stream_get_info(stream_env->stream,
 510                                   &stream_env->stream_info) != 0) {
 511                ia_css_stream_destroy(stream_env->stream);
 512                stream_env->stream = NULL;
 513                return -EINVAL;
 514        }
 515
 516        stream_env->stream_state = CSS_STREAM_CREATED;
 517        return 0;
 518}
 519
 520static int __create_streams(struct atomisp_sub_device *asd)
 521{
 522        int ret, i;
 523
 524        for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
 525                ret = __create_stream(asd, &asd->stream_env[i]);
 526                if (ret)
 527                        goto rollback;
 528        }
 529        asd->stream_prepared = true;
 530        return 0;
 531rollback:
 532        for (i--; i >= 0; i--)
 533                __destroy_stream(asd, &asd->stream_env[i], true);
 534        return ret;
 535}
 536
 537static int __destroy_stream_pipes(struct atomisp_sub_device *asd,
 538                                  struct atomisp_stream_env *stream_env,
 539                                  bool force)
 540{
 541        struct atomisp_device *isp = asd->isp;
 542        int ret = 0;
 543        int i;
 544
 545        for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) {
 546                if (!stream_env->pipes[i] ||
 547                    !(force || stream_env->update_pipe[i]))
 548                        continue;
 549                if (ia_css_pipe_destroy(stream_env->pipes[i])
 550                    != 0) {
 551                        dev_err(isp->dev,
 552                                "destroy pipe[%d]failed.cannot recover.\n", i);
 553                        ret = -EINVAL;
 554                }
 555                stream_env->pipes[i] = NULL;
 556                stream_env->update_pipe[i] = false;
 557        }
 558        return ret;
 559}
 560
 561static int __destroy_pipes(struct atomisp_sub_device *asd, bool force)
 562{
 563        struct atomisp_device *isp = asd->isp;
 564        int i;
 565        int ret = 0;
 566
 567        for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
 568                if (asd->stream_env[i].stream) {
 569                        dev_err(isp->dev,
 570                                "cannot destroy css pipes for stream[%d].\n",
 571                                i);
 572                        continue;
 573                }
 574
 575                ret = __destroy_stream_pipes(asd, &asd->stream_env[i], force);
 576                if (ret)
 577                        return ret;
 578        }
 579
 580        return 0;
 581}
 582
 583void atomisp_destroy_pipes_stream_force(struct atomisp_sub_device *asd)
 584{
 585        __destroy_streams(asd, true);
 586        __destroy_pipes(asd, true);
 587}
 588
 589static void __apply_additional_pipe_config(
 590    struct atomisp_sub_device *asd,
 591    struct atomisp_stream_env *stream_env,
 592    enum ia_css_pipe_id pipe_id)
 593{
 594        struct atomisp_device *isp = asd->isp;
 595
 596        if (pipe_id < 0 || pipe_id >= IA_CSS_PIPE_ID_NUM) {
 597                dev_err(isp->dev,
 598                        "wrong pipe_id for additional pipe config.\n");
 599                return;
 600        }
 601
 602        /* apply default pipe config */
 603        stream_env->pipe_configs[pipe_id].isp_pipe_version = 2;
 604        stream_env->pipe_configs[pipe_id].enable_dz =
 605            asd->disable_dz->val ? false : true;
 606        /* apply isp 2.2 specific config for baytrail*/
 607        switch (pipe_id) {
 608        case IA_CSS_PIPE_ID_CAPTURE:
 609                /* enable capture pp/dz manually or digital zoom would
 610                 * fail*/
 611                if (stream_env->pipe_configs[pipe_id].
 612                    default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW)
 613                        stream_env->pipe_configs[pipe_id].enable_dz = false;
 614
 615                if (IS_ISP2401) {
 616                        /* the isp default to use ISP2.2 and the camera hal will
 617                        * control whether use isp2.7 */
 618                        if (asd->select_isp_version->val == ATOMISP_CSS_ISP_PIPE_VERSION_2_7)
 619                                stream_env->pipe_configs[pipe_id].isp_pipe_version =  SH_CSS_ISP_PIPE_VERSION_2_7;
 620                        else
 621                                stream_env->pipe_configs[pipe_id].isp_pipe_version = SH_CSS_ISP_PIPE_VERSION_2_2;
 622                }
 623                break;
 624        case IA_CSS_PIPE_ID_VIDEO:
 625                /* enable reduced pipe to have binary
 626                 * video_dz_2_min selected*/
 627                stream_env->pipe_extra_configs[pipe_id]
 628                .enable_reduced_pipe = true;
 629                stream_env->pipe_configs[pipe_id]
 630                .enable_dz = false;
 631                if (ATOMISP_SOC_CAMERA(asd))
 632                        stream_env->pipe_configs[pipe_id].enable_dz = true;
 633
 634                if (asd->params.video_dis_en) {
 635                        stream_env->pipe_extra_configs[pipe_id]
 636                        .enable_dvs_6axis = true;
 637                        stream_env->pipe_configs[pipe_id]
 638                        .dvs_frame_delay =
 639                            ATOMISP_CSS2_NUM_DVS_FRAME_DELAY;
 640                }
 641                break;
 642        case IA_CSS_PIPE_ID_PREVIEW:
 643                break;
 644        case IA_CSS_PIPE_ID_YUVPP:
 645        case IA_CSS_PIPE_ID_COPY:
 646                if (ATOMISP_SOC_CAMERA(asd))
 647                        stream_env->pipe_configs[pipe_id].enable_dz = true;
 648                else
 649                        stream_env->pipe_configs[pipe_id].enable_dz = false;
 650                break;
 651        case IA_CSS_PIPE_ID_ACC:
 652                stream_env->pipe_configs[pipe_id].mode = IA_CSS_PIPE_MODE_ACC;
 653                stream_env->pipe_configs[pipe_id].enable_dz = false;
 654                break;
 655        default:
 656                break;
 657        }
 658}
 659
 660static bool is_pipe_valid_to_current_run_mode(struct atomisp_sub_device *asd,
 661        enum ia_css_pipe_id pipe_id)
 662{
 663        if (!asd)
 664                return false;
 665
 666        if (pipe_id == IA_CSS_PIPE_ID_ACC || pipe_id == IA_CSS_PIPE_ID_YUVPP)
 667                return true;
 668
 669        if (asd->vfpp) {
 670                if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
 671                        if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
 672                                return true;
 673                        else
 674                                return false;
 675                } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
 676                        if (pipe_id == IA_CSS_PIPE_ID_CAPTURE)
 677                                return true;
 678                        else
 679                                return false;
 680                }
 681        }
 682
 683        if (!asd->run_mode)
 684                return false;
 685
 686        if (asd->copy_mode && pipe_id == IA_CSS_PIPE_ID_COPY)
 687                return true;
 688
 689        switch (asd->run_mode->val) {
 690        case ATOMISP_RUN_MODE_STILL_CAPTURE:
 691                if (pipe_id == IA_CSS_PIPE_ID_CAPTURE)
 692                        return true;
 693
 694                return false;
 695        case ATOMISP_RUN_MODE_PREVIEW:
 696                if (!asd->continuous_mode->val) {
 697                        if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
 698                                return true;
 699
 700                        return false;
 701                }
 702                fallthrough;
 703        case ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE:
 704                if (pipe_id == IA_CSS_PIPE_ID_CAPTURE ||
 705                    pipe_id == IA_CSS_PIPE_ID_PREVIEW)
 706                        return true;
 707
 708                return false;
 709        case ATOMISP_RUN_MODE_VIDEO:
 710                if (!asd->continuous_mode->val) {
 711                        if (pipe_id == IA_CSS_PIPE_ID_VIDEO ||
 712                            pipe_id == IA_CSS_PIPE_ID_YUVPP)
 713                                return true;
 714                        else
 715                                return false;
 716                }
 717                fallthrough;
 718        case ATOMISP_RUN_MODE_SDV:
 719                if (pipe_id == IA_CSS_PIPE_ID_CAPTURE ||
 720                    pipe_id == IA_CSS_PIPE_ID_VIDEO)
 721                        return true;
 722
 723                return false;
 724        }
 725
 726        return false;
 727}
 728
 729static int __create_pipe(struct atomisp_sub_device *asd,
 730                         struct atomisp_stream_env *stream_env,
 731                         enum ia_css_pipe_id pipe_id)
 732{
 733        struct atomisp_device *isp = asd->isp;
 734        struct ia_css_pipe_extra_config extra_config;
 735        int ret;
 736
 737        if (pipe_id >= IA_CSS_PIPE_ID_NUM)
 738                return -EINVAL;
 739
 740        if (pipe_id != IA_CSS_PIPE_ID_ACC &&
 741            !stream_env->pipe_configs[pipe_id].output_info[0].res.width)
 742                return 0;
 743
 744        if (pipe_id == IA_CSS_PIPE_ID_ACC &&
 745            !stream_env->pipe_configs[pipe_id].acc_extension)
 746                return 0;
 747
 748        if (!is_pipe_valid_to_current_run_mode(asd, pipe_id))
 749                return 0;
 750
 751        ia_css_pipe_extra_config_defaults(&extra_config);
 752
 753        __apply_additional_pipe_config(asd, stream_env, pipe_id);
 754        if (!memcmp(&extra_config,
 755                    &stream_env->pipe_extra_configs[pipe_id],
 756                    sizeof(extra_config)))
 757                ret = ia_css_pipe_create(
 758                          &stream_env->pipe_configs[pipe_id],
 759                          &stream_env->pipes[pipe_id]);
 760        else
 761                ret = ia_css_pipe_create_extra(
 762                          &stream_env->pipe_configs[pipe_id],
 763                          &stream_env->pipe_extra_configs[pipe_id],
 764                          &stream_env->pipes[pipe_id]);
 765        if (ret)
 766                dev_err(isp->dev, "create pipe[%d] error.\n", pipe_id);
 767        return ret;
 768}
 769
 770static int __create_pipes(struct atomisp_sub_device *asd)
 771{
 772        int ret;
 773        int i, j;
 774
 775        for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
 776                for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) {
 777                        ret = __create_pipe(asd, &asd->stream_env[i], j);
 778                        if (ret)
 779                                break;
 780                }
 781                if (j < IA_CSS_PIPE_ID_NUM)
 782                        goto pipe_err;
 783        }
 784        return 0;
 785pipe_err:
 786        for (; i >= 0; i--) {
 787                for (j--; j >= 0; j--) {
 788                        if (asd->stream_env[i].pipes[j]) {
 789                                ia_css_pipe_destroy(asd->stream_env[i].pipes[j]);
 790                                asd->stream_env[i].pipes[j] = NULL;
 791                        }
 792                }
 793                j = IA_CSS_PIPE_ID_NUM;
 794        }
 795        return -EINVAL;
 796}
 797
 798void atomisp_create_pipes_stream(struct atomisp_sub_device *asd)
 799{
 800        __create_pipes(asd);
 801        __create_streams(asd);
 802}
 803
 804int atomisp_css_update_stream(struct atomisp_sub_device *asd)
 805{
 806        int ret;
 807        struct atomisp_device *isp = asd->isp;
 808
 809        if (__destroy_streams(asd, true))
 810                dev_warn(isp->dev, "destroy stream failed.\n");
 811
 812        if (__destroy_pipes(asd, true))
 813                dev_warn(isp->dev, "destroy pipe failed.\n");
 814
 815        ret = __create_pipes(asd);
 816        if (ret) {
 817                dev_err(isp->dev, "create pipe failed %d.\n", ret);
 818                return -EIO;
 819        }
 820
 821        ret = __create_streams(asd);
 822        if (ret) {
 823                dev_warn(isp->dev, "create stream failed %d.\n", ret);
 824                __destroy_pipes(asd, true);
 825                return -EIO;
 826        }
 827
 828        return 0;
 829}
 830
 831int atomisp_css_init(struct atomisp_device *isp)
 832{
 833        unsigned int mmu_base_addr;
 834        int ret;
 835        int err;
 836
 837        ret = hmm_get_mmu_base_addr(isp->dev, &mmu_base_addr);
 838        if (ret)
 839                return ret;
 840
 841        /* Init ISP */
 842        err = ia_css_init(isp->dev, &isp->css_env.isp_css_env, NULL,
 843                          (uint32_t)mmu_base_addr, IA_CSS_IRQ_TYPE_PULSE);
 844        if (err) {
 845                dev_err(isp->dev, "css init failed --- bad firmware?\n");
 846                return -EINVAL;
 847        }
 848        ia_css_enable_isys_event_queue(true);
 849
 850        isp->css_initialized = true;
 851        dev_dbg(isp->dev, "sh_css_init success\n");
 852
 853        return 0;
 854}
 855
 856static inline int __set_css_print_env(struct atomisp_device *isp, int opt)
 857{
 858        int ret = 0;
 859
 860        if (opt == 0)
 861                isp->css_env.isp_css_env.print_env.debug_print = NULL;
 862        else if (opt == 1)
 863                isp->css_env.isp_css_env.print_env.debug_print =
 864                    atomisp_css2_dbg_ftrace_print;
 865        else if (opt == 2)
 866                isp->css_env.isp_css_env.print_env.debug_print = atomisp_vprintk;
 867        else
 868                ret = -EINVAL;
 869
 870        return ret;
 871}
 872
 873int atomisp_css_load_firmware(struct atomisp_device *isp)
 874{
 875        int err;
 876
 877        /* set css env */
 878        isp->css_env.isp_css_fw.data = (void *)isp->firmware->data;
 879        isp->css_env.isp_css_fw.bytes = isp->firmware->size;
 880
 881        isp->css_env.isp_css_env.hw_access_env.store_8 =
 882            atomisp_css2_hw_store_8;
 883        isp->css_env.isp_css_env.hw_access_env.store_16 =
 884            atomisp_css2_hw_store_16;
 885        isp->css_env.isp_css_env.hw_access_env.store_32 =
 886            atomisp_css2_hw_store_32;
 887
 888        isp->css_env.isp_css_env.hw_access_env.load_8 = atomisp_css2_hw_load_8;
 889        isp->css_env.isp_css_env.hw_access_env.load_16 =
 890            atomisp_css2_hw_load_16;
 891        isp->css_env.isp_css_env.hw_access_env.load_32 =
 892            atomisp_css2_hw_load_32;
 893
 894        isp->css_env.isp_css_env.hw_access_env.load = atomisp_css2_hw_load;
 895        isp->css_env.isp_css_env.hw_access_env.store = atomisp_css2_hw_store;
 896
 897        __set_css_print_env(isp, dbg_func);
 898
 899        isp->css_env.isp_css_env.print_env.error_print = atomisp_vprintk;
 900
 901        /* load isp fw into ISP memory */
 902        err = ia_css_load_firmware(isp->dev, &isp->css_env.isp_css_env,
 903                                   &isp->css_env.isp_css_fw);
 904        if (err) {
 905                dev_err(isp->dev, "css load fw failed.\n");
 906                return -EINVAL;
 907        }
 908
 909        return 0;
 910}
 911
 912void atomisp_css_uninit(struct atomisp_device *isp)
 913{
 914        struct atomisp_sub_device *asd;
 915        unsigned int i;
 916
 917        for (i = 0; i < isp->num_of_streams; i++) {
 918                asd = &isp->asd[i];
 919                memset(&asd->params.config, 0, sizeof(asd->params.config));
 920                asd->params.css_update_params_needed = false;
 921        }
 922
 923        isp->css_initialized = false;
 924        ia_css_uninit();
 925}
 926
 927void atomisp_css_suspend(struct atomisp_device *isp)
 928{
 929        isp->css_initialized = false;
 930        ia_css_uninit();
 931}
 932
 933int atomisp_css_resume(struct atomisp_device *isp)
 934{
 935        unsigned int mmu_base_addr;
 936        int ret;
 937
 938        ret = hmm_get_mmu_base_addr(isp->dev, &mmu_base_addr);
 939        if (ret) {
 940                dev_err(isp->dev, "get base address error.\n");
 941                return -EINVAL;
 942        }
 943
 944        ret = ia_css_init(isp->dev, &isp->css_env.isp_css_env, NULL,
 945                          mmu_base_addr, IA_CSS_IRQ_TYPE_PULSE);
 946        if (ret) {
 947                dev_err(isp->dev, "re-init css failed.\n");
 948                return -EINVAL;
 949        }
 950        ia_css_enable_isys_event_queue(true);
 951
 952        isp->css_initialized = true;
 953        return 0;
 954}
 955
 956int atomisp_css_irq_translate(struct atomisp_device *isp,
 957                              unsigned int *infos)
 958{
 959        int err;
 960
 961        err = ia_css_irq_translate(infos);
 962        if (err) {
 963                dev_warn(isp->dev,
 964                         "%s:failed to translate irq (err = %d,infos = %d)\n",
 965                         __func__, err, *infos);
 966                return -EINVAL;
 967        }
 968
 969        return 0;
 970}
 971
 972void atomisp_css_rx_get_irq_info(enum mipi_port_id port,
 973                                 unsigned int *infos)
 974{
 975#ifndef ISP2401_NEW_INPUT_SYSTEM
 976        ia_css_isys_rx_get_irq_info(port, infos);
 977#else
 978        *infos = 0;
 979#endif
 980}
 981
 982void atomisp_css_rx_clear_irq_info(enum mipi_port_id port,
 983                                   unsigned int infos)
 984{
 985#ifndef ISP2401_NEW_INPUT_SYSTEM
 986        ia_css_isys_rx_clear_irq_info(port, infos);
 987#endif
 988}
 989
 990int atomisp_css_irq_enable(struct atomisp_device *isp,
 991                           enum ia_css_irq_info info, bool enable)
 992{
 993        dev_dbg(isp->dev, "%s: css irq info 0x%08x: %s (%d).\n",
 994                __func__, info,
 995                enable ? "enable" : "disable", enable);
 996        if (ia_css_irq_enable(info, enable)) {
 997                dev_warn(isp->dev, "%s:Invalid irq info: 0x%08x when %s.\n",
 998                         __func__, info,
 999                         enable ? "enabling" : "disabling");
1000                return -EINVAL;
1001        }
1002
1003        return 0;
1004}
1005
1006void atomisp_css_init_struct(struct atomisp_sub_device *asd)
1007{
1008        int i, j;
1009
1010        for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
1011                asd->stream_env[i].stream = NULL;
1012                for (j = 0; j < IA_CSS_PIPE_MODE_NUM; j++) {
1013                        asd->stream_env[i].pipes[j] = NULL;
1014                        asd->stream_env[i].update_pipe[j] = false;
1015                        ia_css_pipe_config_defaults(
1016                            &asd->stream_env[i].pipe_configs[j]);
1017                        ia_css_pipe_extra_config_defaults(
1018                            &asd->stream_env[i].pipe_extra_configs[j]);
1019                }
1020                ia_css_stream_config_defaults(&asd->stream_env[i].stream_config);
1021        }
1022}
1023
1024int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd,
1025                                  struct videobuf_vmalloc_memory *vm_mem,
1026                                  enum atomisp_input_stream_id stream_id,
1027                                  enum ia_css_buffer_type css_buf_type,
1028                                  enum ia_css_pipe_id css_pipe_id)
1029{
1030        struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id];
1031        struct ia_css_buffer css_buf = {0};
1032        int err;
1033
1034        css_buf.type = css_buf_type;
1035        css_buf.data.frame = vm_mem->vaddr;
1036
1037        err = ia_css_pipe_enqueue_buffer(
1038                  stream_env->pipes[css_pipe_id], &css_buf);
1039        if (err)
1040                return -EINVAL;
1041
1042        return 0;
1043}
1044
1045int atomisp_q_metadata_buffer_to_css(struct atomisp_sub_device *asd,
1046                                     struct atomisp_metadata_buf *metadata_buf,
1047                                     enum atomisp_input_stream_id stream_id,
1048                                     enum ia_css_pipe_id css_pipe_id)
1049{
1050        struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id];
1051        struct ia_css_buffer buffer = {0};
1052        struct atomisp_device *isp = asd->isp;
1053
1054        buffer.type = IA_CSS_BUFFER_TYPE_METADATA;
1055        buffer.data.metadata = metadata_buf->metadata;
1056        if (ia_css_pipe_enqueue_buffer(stream_env->pipes[css_pipe_id],
1057                                       &buffer)) {
1058                dev_err(isp->dev, "failed to q meta data buffer\n");
1059                return -EINVAL;
1060        }
1061
1062        return 0;
1063}
1064
1065int atomisp_q_s3a_buffer_to_css(struct atomisp_sub_device *asd,
1066                                struct atomisp_s3a_buf *s3a_buf,
1067                                enum atomisp_input_stream_id stream_id,
1068                                enum ia_css_pipe_id css_pipe_id)
1069{
1070        struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id];
1071        struct ia_css_buffer buffer = {0};
1072        struct atomisp_device *isp = asd->isp;
1073
1074        buffer.type = IA_CSS_BUFFER_TYPE_3A_STATISTICS;
1075        buffer.data.stats_3a = s3a_buf->s3a_data;
1076        if (ia_css_pipe_enqueue_buffer(
1077                stream_env->pipes[css_pipe_id],
1078                &buffer)) {
1079                dev_dbg(isp->dev, "failed to q s3a stat buffer\n");
1080                return -EINVAL;
1081        }
1082
1083        return 0;
1084}
1085
1086int atomisp_q_dis_buffer_to_css(struct atomisp_sub_device *asd,
1087                                struct atomisp_dis_buf *dis_buf,
1088                                enum atomisp_input_stream_id stream_id,
1089                                enum ia_css_pipe_id css_pipe_id)
1090{
1091        struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id];
1092        struct ia_css_buffer buffer = {0};
1093        struct atomisp_device *isp = asd->isp;
1094
1095        buffer.type = IA_CSS_BUFFER_TYPE_DIS_STATISTICS;
1096        buffer.data.stats_dvs = dis_buf->dis_data;
1097        if (ia_css_pipe_enqueue_buffer(
1098                stream_env->pipes[css_pipe_id],
1099                &buffer)) {
1100                dev_dbg(isp->dev, "failed to q dvs stat buffer\n");
1101                return -EINVAL;
1102        }
1103
1104        return 0;
1105}
1106
1107int atomisp_css_start(struct atomisp_sub_device *asd,
1108                      enum ia_css_pipe_id pipe_id, bool in_reset)
1109{
1110        struct atomisp_device *isp = asd->isp;
1111        bool sp_is_started = false;
1112        int ret = 0, i = 0;
1113
1114        if (in_reset) {
1115                if (__destroy_streams(asd, true))
1116                        dev_warn(isp->dev, "destroy stream failed.\n");
1117
1118                if (__destroy_pipes(asd, true))
1119                        dev_warn(isp->dev, "destroy pipe failed.\n");
1120
1121                if (__create_pipes(asd)) {
1122                        dev_err(isp->dev, "create pipe error.\n");
1123                        return -EINVAL;
1124                }
1125                if (__create_streams(asd)) {
1126                        dev_err(isp->dev, "create stream error.\n");
1127                        ret = -EINVAL;
1128                        goto stream_err;
1129                }
1130                /* in_reset == true, extension firmwares are reloaded after the recovery */
1131                atomisp_acc_load_extensions(asd);
1132        }
1133
1134        /*
1135         * For dual steam case, it is possible that:
1136         * 1: for this stream, it is at the stage that:
1137         * - after set_fmt is called
1138         * - before stream on is called
1139         * 2: for the other stream, the stream off is called which css reset
1140         * has been done.
1141         *
1142         * Thus the stream created in set_fmt get destroyed and need to be
1143         * recreated in the next stream on.
1144         */
1145        if (!asd->stream_prepared) {
1146                if (__create_pipes(asd)) {
1147                        dev_err(isp->dev, "create pipe error.\n");
1148                        return -EINVAL;
1149                }
1150                if (__create_streams(asd)) {
1151                        dev_err(isp->dev, "create stream error.\n");
1152                        ret = -EINVAL;
1153                        goto stream_err;
1154                }
1155        }
1156        /*
1157         * SP can only be started one time
1158         * if atomisp_subdev_streaming_count() tell there already has some
1159         * subdev at streamming, then SP should already be started previously,
1160         * so need to skip start sp procedure
1161         */
1162        if (atomisp_streaming_count(isp)) {
1163                dev_dbg(isp->dev, "skip start sp\n");
1164        } else {
1165                if (!sh_css_hrt_system_is_idle())
1166                        dev_err(isp->dev, "CSS HW not idle before starting SP\n");
1167                if (ia_css_start_sp()) {
1168                        dev_err(isp->dev, "start sp error.\n");
1169                        ret = -EINVAL;
1170                        goto start_err;
1171                } else {
1172                        sp_is_started = true;
1173                }
1174        }
1175
1176        for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
1177                if (asd->stream_env[i].stream) {
1178                        if (ia_css_stream_start(asd->stream_env[i]
1179                                                .stream) != 0) {
1180                                dev_err(isp->dev, "stream[%d] start error.\n", i);
1181                                ret = -EINVAL;
1182                                goto start_err;
1183                        } else {
1184                                asd->stream_env[i].stream_state = CSS_STREAM_STARTED;
1185                                dev_dbg(isp->dev, "stream[%d] started.\n", i);
1186                        }
1187                }
1188        }
1189
1190        return 0;
1191
1192start_err:
1193        __destroy_streams(asd, true);
1194stream_err:
1195        __destroy_pipes(asd, true);
1196
1197        /* css 2.0 API limitation: ia_css_stop_sp() could be only called after
1198         * destroy all pipes
1199         */
1200        /*
1201         * SP can not be stop if other streams are in use
1202         */
1203        if ((atomisp_streaming_count(isp) == 0) && sp_is_started)
1204                ia_css_stop_sp();
1205
1206        return ret;
1207}
1208
1209void atomisp_css_update_isp_params(struct atomisp_sub_device *asd)
1210{
1211        /*
1212         * FIXME!
1213         * for ISP2401 new input system, this api is under development.
1214         * Calling it would cause kernel panic.
1215         *
1216         * VIED BZ: 1458
1217         *
1218         * Check if it is Cherry Trail and also new input system
1219         */
1220        if (asd->copy_mode) {
1221                dev_warn(asd->isp->dev,
1222                         "%s: ia_css_stream_set_isp_config() not supported in copy mode!.\n",
1223                         __func__);
1224                return;
1225        }
1226
1227        ia_css_stream_set_isp_config(
1228            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
1229            &asd->params.config);
1230        memset(&asd->params.config, 0, sizeof(asd->params.config));
1231}
1232
1233void atomisp_css_update_isp_params_on_pipe(struct atomisp_sub_device *asd,
1234        struct ia_css_pipe *pipe)
1235{
1236        int ret;
1237
1238        if (!pipe) {
1239                atomisp_css_update_isp_params(asd);
1240                return;
1241        }
1242
1243        dev_dbg(asd->isp->dev,
1244                "%s: apply parameter for ia_css_frame %p with isp_config_id %d on pipe %p.\n",
1245                __func__, asd->params.config.output_frame,
1246                asd->params.config.isp_config_id, pipe);
1247
1248        ret = ia_css_stream_set_isp_config_on_pipe(
1249                  asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
1250                  &asd->params.config, pipe);
1251        if (ret)
1252                dev_warn(asd->isp->dev, "%s: ia_css_stream_set_isp_config_on_pipe failed %d\n",
1253                         __func__, ret);
1254        memset(&asd->params.config, 0, sizeof(asd->params.config));
1255}
1256
1257int atomisp_css_queue_buffer(struct atomisp_sub_device *asd,
1258                             enum atomisp_input_stream_id stream_id,
1259                             enum ia_css_pipe_id pipe_id,
1260                             enum ia_css_buffer_type buf_type,
1261                             struct atomisp_css_buffer *isp_css_buffer)
1262{
1263        if (ia_css_pipe_enqueue_buffer(
1264                asd->stream_env[stream_id].pipes[pipe_id],
1265                &isp_css_buffer->css_buffer)
1266            != 0)
1267                return -EINVAL;
1268
1269        return 0;
1270}
1271
1272int atomisp_css_dequeue_buffer(struct atomisp_sub_device *asd,
1273                               enum atomisp_input_stream_id stream_id,
1274                               enum ia_css_pipe_id pipe_id,
1275                               enum ia_css_buffer_type buf_type,
1276                               struct atomisp_css_buffer *isp_css_buffer)
1277{
1278        struct atomisp_device *isp = asd->isp;
1279        int err;
1280
1281        err = ia_css_pipe_dequeue_buffer(
1282                  asd->stream_env[stream_id].pipes[pipe_id],
1283                  &isp_css_buffer->css_buffer);
1284        if (err) {
1285                dev_err(isp->dev,
1286                        "ia_css_pipe_dequeue_buffer failed: 0x%x\n", err);
1287                return -EINVAL;
1288        }
1289
1290        return 0;
1291}
1292
1293int atomisp_css_allocate_stat_buffers(struct atomisp_sub_device   *asd,
1294                                      u16 stream_id,
1295                                      struct atomisp_s3a_buf      *s3a_buf,
1296                                      struct atomisp_dis_buf      *dis_buf,
1297                                      struct atomisp_metadata_buf *md_buf)
1298{
1299        struct atomisp_device *isp = asd->isp;
1300        struct ia_css_dvs_grid_info *dvs_grid_info =
1301            atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
1302
1303        if (s3a_buf && asd->params.curr_grid_info.s3a_grid.enable) {
1304                void *s3a_ptr;
1305
1306                s3a_buf->s3a_data = ia_css_isp_3a_statistics_allocate(
1307                                        &asd->params.curr_grid_info.s3a_grid);
1308                if (!s3a_buf->s3a_data) {
1309                        dev_err(isp->dev, "3a buf allocation failed.\n");
1310                        return -EINVAL;
1311                }
1312
1313                s3a_ptr = hmm_vmap(s3a_buf->s3a_data->data_ptr, true);
1314                s3a_buf->s3a_map = ia_css_isp_3a_statistics_map_allocate(
1315                                       s3a_buf->s3a_data, s3a_ptr);
1316        }
1317
1318        if (dis_buf && dvs_grid_info && dvs_grid_info->enable) {
1319                void *dvs_ptr;
1320
1321                dis_buf->dis_data = ia_css_isp_dvs2_statistics_allocate(
1322                                        dvs_grid_info);
1323                if (!dis_buf->dis_data) {
1324                        dev_err(isp->dev, "dvs buf allocation failed.\n");
1325                        if (s3a_buf)
1326                                ia_css_isp_3a_statistics_free(s3a_buf->s3a_data);
1327                        return -EINVAL;
1328                }
1329
1330                dvs_ptr = hmm_vmap(dis_buf->dis_data->data_ptr, true);
1331                dis_buf->dvs_map = ia_css_isp_dvs_statistics_map_allocate(
1332                                       dis_buf->dis_data, dvs_ptr);
1333        }
1334
1335        if (asd->stream_env[stream_id].stream_info.
1336            metadata_info.size && md_buf) {
1337                md_buf->metadata = ia_css_metadata_allocate(
1338                                       &asd->stream_env[stream_id].stream_info.metadata_info);
1339                if (!md_buf->metadata) {
1340                        if (s3a_buf)
1341                                ia_css_isp_3a_statistics_free(s3a_buf->s3a_data);
1342                        if (dis_buf)
1343                                ia_css_isp_dvs2_statistics_free(dis_buf->dis_data);
1344                        dev_err(isp->dev, "metadata buf allocation failed.\n");
1345                        return -EINVAL;
1346                }
1347                md_buf->md_vptr = hmm_vmap(md_buf->metadata->address, false);
1348        }
1349
1350        return 0;
1351}
1352
1353void atomisp_css_free_3a_buffer(struct atomisp_s3a_buf *s3a_buf)
1354{
1355        if (s3a_buf->s3a_data)
1356                hmm_vunmap(s3a_buf->s3a_data->data_ptr);
1357
1358        ia_css_isp_3a_statistics_map_free(s3a_buf->s3a_map);
1359        s3a_buf->s3a_map = NULL;
1360        ia_css_isp_3a_statistics_free(s3a_buf->s3a_data);
1361}
1362
1363void atomisp_css_free_dis_buffer(struct atomisp_dis_buf *dis_buf)
1364{
1365        if (dis_buf->dis_data)
1366                hmm_vunmap(dis_buf->dis_data->data_ptr);
1367
1368        ia_css_isp_dvs_statistics_map_free(dis_buf->dvs_map);
1369        dis_buf->dvs_map = NULL;
1370        ia_css_isp_dvs2_statistics_free(dis_buf->dis_data);
1371}
1372
1373void atomisp_css_free_metadata_buffer(struct atomisp_metadata_buf *metadata_buf)
1374{
1375        if (metadata_buf->md_vptr) {
1376                hmm_vunmap(metadata_buf->metadata->address);
1377                metadata_buf->md_vptr = NULL;
1378        }
1379        ia_css_metadata_free(metadata_buf->metadata);
1380}
1381
1382void atomisp_css_free_stat_buffers(struct atomisp_sub_device *asd)
1383{
1384        struct atomisp_s3a_buf *s3a_buf, *_s3a_buf;
1385        struct atomisp_dis_buf *dis_buf, *_dis_buf;
1386        struct atomisp_metadata_buf *md_buf, *_md_buf;
1387        struct ia_css_dvs_grid_info *dvs_grid_info =
1388            atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
1389        unsigned int i;
1390
1391        /* 3A statistics use vmalloc, DIS use kmalloc */
1392        if (dvs_grid_info && dvs_grid_info->enable) {
1393                ia_css_dvs2_coefficients_free(asd->params.css_param.dvs2_coeff);
1394                ia_css_dvs2_statistics_free(asd->params.dvs_stat);
1395                asd->params.css_param.dvs2_coeff = NULL;
1396                asd->params.dvs_stat = NULL;
1397                asd->params.dvs_hor_proj_bytes = 0;
1398                asd->params.dvs_ver_proj_bytes = 0;
1399                asd->params.dvs_hor_coef_bytes = 0;
1400                asd->params.dvs_ver_coef_bytes = 0;
1401                asd->params.dis_proj_data_valid = false;
1402                list_for_each_entry_safe(dis_buf, _dis_buf,
1403                                         &asd->dis_stats, list) {
1404                        atomisp_css_free_dis_buffer(dis_buf);
1405                        list_del(&dis_buf->list);
1406                        kfree(dis_buf);
1407                }
1408                list_for_each_entry_safe(dis_buf, _dis_buf,
1409                                         &asd->dis_stats_in_css, list) {
1410                        atomisp_css_free_dis_buffer(dis_buf);
1411                        list_del(&dis_buf->list);
1412                        kfree(dis_buf);
1413                }
1414        }
1415        if (asd->params.curr_grid_info.s3a_grid.enable) {
1416                ia_css_3a_statistics_free(asd->params.s3a_user_stat);
1417                asd->params.s3a_user_stat = NULL;
1418                asd->params.s3a_output_bytes = 0;
1419                list_for_each_entry_safe(s3a_buf, _s3a_buf,
1420                                         &asd->s3a_stats, list) {
1421                        atomisp_css_free_3a_buffer(s3a_buf);
1422                        list_del(&s3a_buf->list);
1423                        kfree(s3a_buf);
1424                }
1425                list_for_each_entry_safe(s3a_buf, _s3a_buf,
1426                                         &asd->s3a_stats_in_css, list) {
1427                        atomisp_css_free_3a_buffer(s3a_buf);
1428                        list_del(&s3a_buf->list);
1429                        kfree(s3a_buf);
1430                }
1431                list_for_each_entry_safe(s3a_buf, _s3a_buf,
1432                                         &asd->s3a_stats_ready, list) {
1433                        atomisp_css_free_3a_buffer(s3a_buf);
1434                        list_del(&s3a_buf->list);
1435                        kfree(s3a_buf);
1436                }
1437        }
1438
1439        if (asd->params.css_param.dvs_6axis) {
1440                ia_css_dvs2_6axis_config_free(asd->params.css_param.dvs_6axis);
1441                asd->params.css_param.dvs_6axis = NULL;
1442        }
1443
1444        for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
1445                list_for_each_entry_safe(md_buf, _md_buf,
1446                                         &asd->metadata[i], list) {
1447                        atomisp_css_free_metadata_buffer(md_buf);
1448                        list_del(&md_buf->list);
1449                        kfree(md_buf);
1450                }
1451                list_for_each_entry_safe(md_buf, _md_buf,
1452                                         &asd->metadata_in_css[i], list) {
1453                        atomisp_css_free_metadata_buffer(md_buf);
1454                        list_del(&md_buf->list);
1455                        kfree(md_buf);
1456                }
1457                list_for_each_entry_safe(md_buf, _md_buf,
1458                                         &asd->metadata_ready[i], list) {
1459                        atomisp_css_free_metadata_buffer(md_buf);
1460                        list_del(&md_buf->list);
1461                        kfree(md_buf);
1462                }
1463        }
1464        asd->params.metadata_width_size = 0;
1465        atomisp_free_metadata_output_buf(asd);
1466}
1467
1468int atomisp_css_get_grid_info(struct atomisp_sub_device *asd,
1469                              enum ia_css_pipe_id pipe_id,
1470                              int source_pad)
1471{
1472        struct ia_css_pipe_info p_info;
1473        struct ia_css_grid_info old_info;
1474        struct atomisp_device *isp = asd->isp;
1475        int stream_index = atomisp_source_pad_to_stream_id(asd, source_pad);
1476        int md_width = asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
1477                       stream_config.metadata_config.resolution.width;
1478
1479        memset(&p_info, 0, sizeof(struct ia_css_pipe_info));
1480        memset(&old_info, 0, sizeof(struct ia_css_grid_info));
1481
1482        if (ia_css_pipe_get_info(
1483                asd->stream_env[stream_index].pipes[pipe_id],
1484                &p_info) != 0) {
1485                dev_err(isp->dev, "ia_css_pipe_get_info failed\n");
1486                return -EINVAL;
1487        }
1488
1489        memcpy(&old_info, &asd->params.curr_grid_info,
1490               sizeof(struct ia_css_grid_info));
1491        memcpy(&asd->params.curr_grid_info, &p_info.grid_info,
1492               sizeof(struct ia_css_grid_info));
1493        /*
1494         * Record which css pipe enables s3a_grid.
1495         * Currently would have one css pipe that need it
1496         */
1497        if (asd->params.curr_grid_info.s3a_grid.enable) {
1498                if (asd->params.s3a_enabled_pipe != IA_CSS_PIPE_ID_NUM)
1499                        dev_dbg(isp->dev, "css pipe %d enabled s3a grid replaced by: %d.\n",
1500                                asd->params.s3a_enabled_pipe, pipe_id);
1501                asd->params.s3a_enabled_pipe = pipe_id;
1502        }
1503
1504        /* If the grid info has not changed and the buffers for 3A and
1505         * DIS statistics buffers are allocated or buffer size would be zero
1506         * then no need to do anything. */
1507        if (((!memcmp(&old_info, &asd->params.curr_grid_info, sizeof(old_info))
1508              && asd->params.s3a_user_stat && asd->params.dvs_stat)
1509             || asd->params.curr_grid_info.s3a_grid.width == 0
1510             || asd->params.curr_grid_info.s3a_grid.height == 0)
1511            && asd->params.metadata_width_size == md_width) {
1512                dev_dbg(isp->dev,
1513                        "grid info change escape. memcmp=%d, s3a_user_stat=%d,dvs_stat=%d, s3a.width=%d, s3a.height=%d, metadata width =%d\n",
1514                        !memcmp(&old_info, &asd->params.curr_grid_info,
1515                                sizeof(old_info)),
1516                        !!asd->params.s3a_user_stat, !!asd->params.dvs_stat,
1517                        asd->params.curr_grid_info.s3a_grid.width,
1518                        asd->params.curr_grid_info.s3a_grid.height,
1519                        asd->params.metadata_width_size);
1520                return -EINVAL;
1521        }
1522        asd->params.metadata_width_size = md_width;
1523
1524        return 0;
1525}
1526
1527int atomisp_alloc_3a_output_buf(struct atomisp_sub_device *asd)
1528{
1529        if (!asd->params.curr_grid_info.s3a_grid.width ||
1530            !asd->params.curr_grid_info.s3a_grid.height)
1531                return 0;
1532
1533        asd->params.s3a_user_stat = ia_css_3a_statistics_allocate(
1534                                        &asd->params.curr_grid_info.s3a_grid);
1535        if (!asd->params.s3a_user_stat)
1536                return -ENOMEM;
1537        /* 3A statistics. These can be big, so we use vmalloc. */
1538        asd->params.s3a_output_bytes =
1539            asd->params.curr_grid_info.s3a_grid.width *
1540            asd->params.curr_grid_info.s3a_grid.height *
1541            sizeof(*asd->params.s3a_user_stat->data);
1542
1543        return 0;
1544}
1545
1546int atomisp_alloc_dis_coef_buf(struct atomisp_sub_device *asd)
1547{
1548        struct ia_css_dvs_grid_info *dvs_grid =
1549            atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
1550
1551        if (!dvs_grid)
1552                return 0;
1553
1554        if (!dvs_grid->enable) {
1555                dev_dbg(asd->isp->dev, "%s: dvs_grid not enabled.\n", __func__);
1556                return 0;
1557        }
1558
1559        /* DIS coefficients. */
1560        asd->params.css_param.dvs2_coeff = ia_css_dvs2_coefficients_allocate(
1561                                               dvs_grid);
1562        if (!asd->params.css_param.dvs2_coeff)
1563                return -ENOMEM;
1564
1565        asd->params.dvs_hor_coef_bytes = dvs_grid->num_hor_coefs *
1566                                         sizeof(*asd->params.css_param.dvs2_coeff->hor_coefs.odd_real);
1567
1568        asd->params.dvs_ver_coef_bytes = dvs_grid->num_ver_coefs *
1569                                         sizeof(*asd->params.css_param.dvs2_coeff->ver_coefs.odd_real);
1570
1571        /* DIS projections. */
1572        asd->params.dis_proj_data_valid = false;
1573        asd->params.dvs_stat = ia_css_dvs2_statistics_allocate(dvs_grid);
1574        if (!asd->params.dvs_stat)
1575                return -ENOMEM;
1576
1577        asd->params.dvs_hor_proj_bytes =
1578            dvs_grid->aligned_height * dvs_grid->aligned_width *
1579            sizeof(*asd->params.dvs_stat->hor_prod.odd_real);
1580
1581        asd->params.dvs_ver_proj_bytes =
1582            dvs_grid->aligned_height * dvs_grid->aligned_width *
1583            sizeof(*asd->params.dvs_stat->ver_prod.odd_real);
1584
1585        return 0;
1586}
1587
1588int atomisp_alloc_metadata_output_buf(struct atomisp_sub_device *asd)
1589{
1590        int i;
1591
1592        /* We allocate the cpu-side buffer used for communication with user
1593         * space */
1594        for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
1595                asd->params.metadata_user[i] = kvmalloc(
1596                                                   asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
1597                                                   stream_info.metadata_info.size, GFP_KERNEL);
1598                if (!asd->params.metadata_user[i]) {
1599                        while (--i >= 0) {
1600                                kvfree(asd->params.metadata_user[i]);
1601                                asd->params.metadata_user[i] = NULL;
1602                        }
1603                        return -ENOMEM;
1604                }
1605        }
1606
1607        return 0;
1608}
1609
1610void atomisp_free_metadata_output_buf(struct atomisp_sub_device *asd)
1611{
1612        unsigned int i;
1613
1614        for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
1615                if (asd->params.metadata_user[i]) {
1616                        kvfree(asd->params.metadata_user[i]);
1617                        asd->params.metadata_user[i] = NULL;
1618                }
1619        }
1620}
1621
1622void atomisp_css_get_dis_statistics(struct atomisp_sub_device *asd,
1623                                    struct atomisp_css_buffer *isp_css_buffer,
1624                                    struct ia_css_isp_dvs_statistics_map *dvs_map)
1625{
1626        if (asd->params.dvs_stat) {
1627                if (dvs_map)
1628                        ia_css_translate_dvs2_statistics(
1629                            asd->params.dvs_stat, dvs_map);
1630                else
1631                        ia_css_get_dvs2_statistics(asd->params.dvs_stat,
1632                                                   isp_css_buffer->css_buffer.data.stats_dvs);
1633        }
1634}
1635
1636int atomisp_css_dequeue_event(struct atomisp_css_event *current_event)
1637{
1638        if (ia_css_dequeue_event(&current_event->event))
1639                return -EINVAL;
1640
1641        return 0;
1642}
1643
1644void atomisp_css_temp_pipe_to_pipe_id(struct atomisp_sub_device *asd,
1645                                      struct atomisp_css_event *current_event)
1646{
1647        /*
1648         * FIXME!
1649         * Pipe ID reported in CSS event is not correct for new system's
1650         * copy pipe.
1651         * VIED BZ: 1463
1652         */
1653        ia_css_temp_pipe_to_pipe_id(current_event->event.pipe,
1654                                    &current_event->pipe);
1655        if (asd && asd->copy_mode &&
1656            current_event->pipe == IA_CSS_PIPE_ID_CAPTURE)
1657                current_event->pipe = IA_CSS_PIPE_ID_COPY;
1658}
1659
1660int atomisp_css_isys_set_resolution(struct atomisp_sub_device *asd,
1661                                    enum atomisp_input_stream_id stream_id,
1662                                    struct v4l2_mbus_framefmt *ffmt,
1663                                    int isys_stream)
1664{
1665        struct ia_css_stream_config *s_config =
1666                    &asd->stream_env[stream_id].stream_config;
1667
1668        if (isys_stream >= IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH)
1669                return -EINVAL;
1670
1671        s_config->isys_config[isys_stream].input_res.width = ffmt->width;
1672        s_config->isys_config[isys_stream].input_res.height = ffmt->height;
1673        return 0;
1674}
1675
1676int atomisp_css_input_set_resolution(struct atomisp_sub_device *asd,
1677                                     enum atomisp_input_stream_id stream_id,
1678                                     struct v4l2_mbus_framefmt *ffmt)
1679{
1680        struct ia_css_stream_config *s_config =
1681                    &asd->stream_env[stream_id].stream_config;
1682
1683        s_config->input_config.input_res.width = ffmt->width;
1684        s_config->input_config.input_res.height = ffmt->height;
1685        return 0;
1686}
1687
1688void atomisp_css_input_set_binning_factor(struct atomisp_sub_device *asd,
1689        enum atomisp_input_stream_id stream_id,
1690        unsigned int bin_factor)
1691{
1692        asd->stream_env[stream_id]
1693        .stream_config.sensor_binning_factor = bin_factor;
1694}
1695
1696void atomisp_css_input_set_bayer_order(struct atomisp_sub_device *asd,
1697                                       enum atomisp_input_stream_id stream_id,
1698                                       enum ia_css_bayer_order bayer_order)
1699{
1700        struct ia_css_stream_config *s_config =
1701                    &asd->stream_env[stream_id].stream_config;
1702        s_config->input_config.bayer_order = bayer_order;
1703}
1704
1705void atomisp_css_isys_set_link(struct atomisp_sub_device *asd,
1706                               enum atomisp_input_stream_id stream_id,
1707                               int link,
1708                               int isys_stream)
1709{
1710        struct ia_css_stream_config *s_config =
1711                    &asd->stream_env[stream_id].stream_config;
1712
1713        s_config->isys_config[isys_stream].linked_isys_stream_id = link;
1714}
1715
1716void atomisp_css_isys_set_valid(struct atomisp_sub_device *asd,
1717                                enum atomisp_input_stream_id stream_id,
1718                                bool valid,
1719                                int isys_stream)
1720{
1721        struct ia_css_stream_config *s_config =
1722                    &asd->stream_env[stream_id].stream_config;
1723
1724        s_config->isys_config[isys_stream].valid = valid;
1725}
1726
1727void atomisp_css_isys_set_format(struct atomisp_sub_device *asd,
1728                                 enum atomisp_input_stream_id stream_id,
1729                                 enum atomisp_input_format format,
1730                                 int isys_stream)
1731{
1732        struct ia_css_stream_config *s_config =
1733                    &asd->stream_env[stream_id].stream_config;
1734
1735        s_config->isys_config[isys_stream].format = format;
1736}
1737
1738void atomisp_css_input_set_format(struct atomisp_sub_device *asd,
1739                                  enum atomisp_input_stream_id stream_id,
1740                                  enum atomisp_input_format format)
1741{
1742        struct ia_css_stream_config *s_config =
1743                    &asd->stream_env[stream_id].stream_config;
1744
1745        s_config->input_config.format = format;
1746}
1747
1748int atomisp_css_set_default_isys_config(struct atomisp_sub_device *asd,
1749                                        enum atomisp_input_stream_id stream_id,
1750                                        struct v4l2_mbus_framefmt *ffmt)
1751{
1752        int i;
1753        struct ia_css_stream_config *s_config =
1754                    &asd->stream_env[stream_id].stream_config;
1755        /*
1756         * Set all isys configs to not valid.
1757         * Currently we support only one stream per channel
1758         */
1759        for (i = IA_CSS_STREAM_ISYS_STREAM_0;
1760             i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++)
1761                s_config->isys_config[i].valid = false;
1762
1763        atomisp_css_isys_set_resolution(asd, stream_id, ffmt,
1764                                        IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
1765        atomisp_css_isys_set_format(asd, stream_id,
1766                                    s_config->input_config.format,
1767                                    IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
1768        atomisp_css_isys_set_link(asd, stream_id, NO_LINK,
1769                                  IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
1770        atomisp_css_isys_set_valid(asd, stream_id, true,
1771                                   IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
1772
1773        return 0;
1774}
1775
1776int atomisp_css_isys_two_stream_cfg(struct atomisp_sub_device *asd,
1777                                    enum atomisp_input_stream_id stream_id,
1778                                    enum atomisp_input_format input_format)
1779{
1780        struct ia_css_stream_config *s_config =
1781                    &asd->stream_env[stream_id].stream_config;
1782
1783        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.width =
1784            s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.width;
1785
1786        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.height =
1787            s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.height / 2;
1788
1789        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].linked_isys_stream_id
1790            = IA_CSS_STREAM_ISYS_STREAM_0;
1791        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].format =
1792            ATOMISP_INPUT_FORMAT_USER_DEF1;
1793        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].format =
1794            ATOMISP_INPUT_FORMAT_USER_DEF2;
1795        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].valid = true;
1796        return 0;
1797}
1798
1799void atomisp_css_isys_two_stream_cfg_update_stream1(
1800    struct atomisp_sub_device *asd,
1801    enum atomisp_input_stream_id stream_id,
1802    enum atomisp_input_format input_format,
1803    unsigned int width, unsigned int height)
1804{
1805        struct ia_css_stream_config *s_config =
1806                    &asd->stream_env[stream_id].stream_config;
1807
1808        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.width =
1809            width;
1810        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.height =
1811            height;
1812        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].format =
1813            input_format;
1814        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].valid = true;
1815}
1816
1817void atomisp_css_isys_two_stream_cfg_update_stream2(
1818    struct atomisp_sub_device *asd,
1819    enum atomisp_input_stream_id stream_id,
1820    enum atomisp_input_format input_format,
1821    unsigned int width, unsigned int height)
1822{
1823        struct ia_css_stream_config *s_config =
1824                    &asd->stream_env[stream_id].stream_config;
1825
1826        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.width =
1827            width;
1828        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.height =
1829            height;
1830        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].linked_isys_stream_id
1831            = IA_CSS_STREAM_ISYS_STREAM_0;
1832        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].format =
1833            input_format;
1834        s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].valid = true;
1835}
1836
1837int atomisp_css_input_set_effective_resolution(
1838    struct atomisp_sub_device *asd,
1839    enum atomisp_input_stream_id stream_id,
1840    unsigned int width, unsigned int height)
1841{
1842        struct ia_css_stream_config *s_config =
1843                    &asd->stream_env[stream_id].stream_config;
1844        s_config->input_config.effective_res.width = width;
1845        s_config->input_config.effective_res.height = height;
1846        return 0;
1847}
1848
1849void atomisp_css_video_set_dis_envelope(struct atomisp_sub_device *asd,
1850                                        unsigned int dvs_w, unsigned int dvs_h)
1851{
1852        asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1853        .pipe_configs[IA_CSS_PIPE_ID_VIDEO].dvs_envelope.width = dvs_w;
1854        asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1855        .pipe_configs[IA_CSS_PIPE_ID_VIDEO].dvs_envelope.height = dvs_h;
1856}
1857
1858void atomisp_css_input_set_two_pixels_per_clock(
1859    struct atomisp_sub_device *asd,
1860    bool two_ppc)
1861{
1862        int i;
1863
1864        if (asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1865            .stream_config.pixels_per_clock == (two_ppc ? 2 : 1))
1866                return;
1867
1868        asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1869        .stream_config.pixels_per_clock = (two_ppc ? 2 : 1);
1870        for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
1871                asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1872                .update_pipe[i] = true;
1873}
1874
1875void atomisp_css_enable_raw_binning(struct atomisp_sub_device *asd,
1876                                    bool enable)
1877{
1878        struct atomisp_stream_env *stream_env =
1879                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
1880        unsigned int pipe;
1881
1882        if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
1883                pipe = IA_CSS_PIPE_ID_VIDEO;
1884        else
1885                pipe = IA_CSS_PIPE_ID_PREVIEW;
1886
1887        stream_env->pipe_extra_configs[pipe].enable_raw_binning = enable;
1888        stream_env->update_pipe[pipe] = true;
1889        if (enable)
1890                stream_env->pipe_configs[pipe].output_info[0].padded_width =
1891                    stream_env->stream_config.input_config.effective_res.width;
1892}
1893
1894void atomisp_css_enable_dz(struct atomisp_sub_device *asd, bool enable)
1895{
1896        int i;
1897
1898        for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
1899                asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1900                .pipe_configs[i].enable_dz = enable;
1901}
1902
1903void atomisp_css_capture_set_mode(struct atomisp_sub_device *asd,
1904                                  enum ia_css_capture_mode mode)
1905{
1906        struct atomisp_stream_env *stream_env =
1907                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
1908
1909        if (stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE]
1910            .default_capture_config.mode == mode)
1911                return;
1912
1913        stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE].
1914        default_capture_config.mode = mode;
1915        stream_env->update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true;
1916}
1917
1918void atomisp_css_input_set_mode(struct atomisp_sub_device *asd,
1919                                enum ia_css_input_mode mode)
1920{
1921        int i;
1922        struct atomisp_device *isp = asd->isp;
1923        unsigned int size_mem_words;
1924
1925        for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++)
1926                asd->stream_env[i].stream_config.mode = mode;
1927
1928        if (isp->inputs[asd->input_curr].type == TEST_PATTERN) {
1929                struct ia_css_stream_config *s_config =
1930                            &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_config;
1931                s_config->mode = IA_CSS_INPUT_MODE_TPG;
1932                s_config->source.tpg.mode = IA_CSS_TPG_MODE_CHECKERBOARD;
1933                s_config->source.tpg.x_mask = (1 << 4) - 1;
1934                s_config->source.tpg.x_delta = -2;
1935                s_config->source.tpg.y_mask = (1 << 4) - 1;
1936                s_config->source.tpg.y_delta = 3;
1937                s_config->source.tpg.xy_mask = (1 << 8) - 1;
1938                return;
1939        }
1940
1941        if (mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
1942                return;
1943
1944        for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
1945                /*
1946                 * TODO: sensor needs to export the embedded_data_size_words
1947                 * information to atomisp for each setting.
1948                 * Here using a large safe value.
1949                 */
1950                struct ia_css_stream_config *s_config =
1951                            &asd->stream_env[i].stream_config;
1952
1953                if (s_config->input_config.input_res.width == 0)
1954                        continue;
1955
1956                if (ia_css_mipi_frame_calculate_size(
1957                        s_config->input_config.input_res.width,
1958                        s_config->input_config.input_res.height,
1959                        s_config->input_config.format,
1960                        true,
1961                        0x13000,
1962                        &size_mem_words) != 0) {
1963                        if (IS_MRFD)
1964                                size_mem_words = CSS_MIPI_FRAME_BUFFER_SIZE_2;
1965                        else
1966                                size_mem_words = CSS_MIPI_FRAME_BUFFER_SIZE_1;
1967                        dev_warn(asd->isp->dev,
1968                                 "ia_css_mipi_frame_calculate_size failed,applying pre-defined MIPI buffer size %u.\n",
1969                                 size_mem_words);
1970                }
1971                s_config->mipi_buffer_config.size_mem_words = size_mem_words;
1972                s_config->mipi_buffer_config.nof_mipi_buffers = 2;
1973        }
1974}
1975
1976void atomisp_css_capture_enable_online(struct atomisp_sub_device *asd,
1977                                       unsigned short stream_index, bool enable)
1978{
1979        struct atomisp_stream_env *stream_env =
1980                    &asd->stream_env[stream_index];
1981
1982        if (stream_env->stream_config.online == !!enable)
1983                return;
1984
1985        stream_env->stream_config.online = !!enable;
1986        stream_env->update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true;
1987}
1988
1989void atomisp_css_preview_enable_online(struct atomisp_sub_device *asd,
1990                                       unsigned short stream_index, bool enable)
1991{
1992        struct atomisp_stream_env *stream_env =
1993                    &asd->stream_env[stream_index];
1994        int i;
1995
1996        if (stream_env->stream_config.online != !!enable) {
1997                stream_env->stream_config.online = !!enable;
1998                for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
1999                        stream_env->update_pipe[i] = true;
2000        }
2001}
2002
2003void atomisp_css_video_enable_online(struct atomisp_sub_device *asd,
2004                                     bool enable)
2005{
2006        struct atomisp_stream_env *stream_env =
2007                    &asd->stream_env[ATOMISP_INPUT_STREAM_VIDEO];
2008        int i;
2009
2010        if (stream_env->stream_config.online != enable) {
2011                stream_env->stream_config.online = enable;
2012                for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
2013                        stream_env->update_pipe[i] = true;
2014        }
2015}
2016
2017void atomisp_css_enable_continuous(struct atomisp_sub_device *asd,
2018                                   bool enable)
2019{
2020        struct atomisp_stream_env *stream_env =
2021                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2022        int i;
2023
2024        /*
2025         * To SOC camera, there is only one YUVPP pipe in any case
2026         * including ZSL/SDV/continuous viewfinder, so always set
2027         * stream_config.continuous to 0.
2028         */
2029        if (ATOMISP_USE_YUVPP(asd)) {
2030                stream_env->stream_config.continuous = 0;
2031                stream_env->stream_config.online = 1;
2032                return;
2033        }
2034
2035        if (stream_env->stream_config.continuous != !!enable) {
2036                stream_env->stream_config.continuous = !!enable;
2037                stream_env->stream_config.pack_raw_pixels = true;
2038                for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
2039                        stream_env->update_pipe[i] = true;
2040        }
2041}
2042
2043void atomisp_css_enable_cvf(struct atomisp_sub_device *asd,
2044                            bool enable)
2045{
2046        struct atomisp_stream_env *stream_env =
2047                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2048        int i;
2049
2050        if (stream_env->stream_config.disable_cont_viewfinder != !enable) {
2051                stream_env->stream_config.disable_cont_viewfinder = !enable;
2052                for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
2053                        stream_env->update_pipe[i] = true;
2054        }
2055}
2056
2057int atomisp_css_input_configure_port(
2058    struct atomisp_sub_device *asd,
2059    enum mipi_port_id port,
2060    unsigned int num_lanes,
2061    unsigned int timeout,
2062    unsigned int mipi_freq,
2063    enum atomisp_input_format metadata_format,
2064    unsigned int metadata_width,
2065    unsigned int metadata_height)
2066{
2067        int i;
2068        struct atomisp_stream_env *stream_env;
2069        /*
2070         * Calculate rx_count as follows:
2071         * Input: mipi_freq                 : CSI-2 bus frequency in Hz
2072         * UI = 1 / (2 * mipi_freq)         : period of one bit on the bus
2073         * min = 85e-9 + 6 * UI             : Limits for rx_count in seconds
2074         * max = 145e-9 + 10 * UI
2075         * rxcount0 = min / (4 / mipi_freq) : convert seconds to byte clocks
2076         * rxcount = rxcount0 - 2           : adjust for better results
2077         * The formula below is simplified version of the above with
2078         * 10-bit fixed points for improved accuracy.
2079         */
2080        const unsigned int rxcount =
2081            min(((mipi_freq / 46000) - 1280) >> 10, 0xffU) * 0x01010101U;
2082
2083        for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
2084                stream_env = &asd->stream_env[i];
2085                stream_env->stream_config.source.port.port = port;
2086                stream_env->stream_config.source.port.num_lanes = num_lanes;
2087                stream_env->stream_config.source.port.timeout = timeout;
2088                if (mipi_freq)
2089                        stream_env->stream_config.source.port.rxcount = rxcount;
2090                stream_env->stream_config.
2091                metadata_config.data_type = metadata_format;
2092                stream_env->stream_config.
2093                metadata_config.resolution.width = metadata_width;
2094                stream_env->stream_config.
2095                metadata_config.resolution.height = metadata_height;
2096        }
2097
2098        return 0;
2099}
2100
2101void atomisp_css_stop(struct atomisp_sub_device *asd,
2102                      enum ia_css_pipe_id pipe_id, bool in_reset)
2103{
2104        struct atomisp_device *isp = asd->isp;
2105        unsigned long irqflags;
2106        unsigned int i;
2107
2108        /* if is called in atomisp_reset(), force destroy stream */
2109        if (__destroy_streams(asd, true))
2110                dev_err(isp->dev, "destroy stream failed.\n");
2111
2112        /* if is called in atomisp_reset(), force destroy all pipes */
2113        if (__destroy_pipes(asd, true))
2114                dev_err(isp->dev, "destroy pipes failed.\n");
2115
2116        atomisp_init_raw_buffer_bitmap(asd);
2117
2118        /*
2119         * SP can not be stop if other streams are in use
2120         */
2121        if (atomisp_streaming_count(isp) == 0)
2122                ia_css_stop_sp();
2123
2124        if (!in_reset) {
2125                struct atomisp_stream_env *stream_env;
2126                int i, j;
2127
2128                for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
2129                        stream_env = &asd->stream_env[i];
2130                        for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) {
2131                                ia_css_pipe_config_defaults(
2132                                    &stream_env->pipe_configs[j]);
2133                                ia_css_pipe_extra_config_defaults(
2134                                    &stream_env->pipe_extra_configs[j]);
2135                        }
2136                        ia_css_stream_config_defaults(
2137                            &stream_env->stream_config);
2138                }
2139                memset(&asd->params.config, 0, sizeof(asd->params.config));
2140                asd->params.css_update_params_needed = false;
2141        }
2142
2143        /* move stats buffers to free queue list */
2144        list_splice_init(&asd->s3a_stats_in_css, &asd->s3a_stats);
2145        list_splice_init(&asd->s3a_stats_ready, &asd->s3a_stats);
2146
2147        spin_lock_irqsave(&asd->dis_stats_lock, irqflags);
2148        list_splice_init(&asd->dis_stats_in_css, &asd->dis_stats);
2149        asd->params.dis_proj_data_valid = false;
2150        spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags);
2151
2152        for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
2153                list_splice_init(&asd->metadata_in_css[i], &asd->metadata[i]);
2154                list_splice_init(&asd->metadata_ready[i], &asd->metadata[i]);
2155        }
2156
2157        atomisp_flush_params_queue(&asd->video_out_capture);
2158        atomisp_flush_params_queue(&asd->video_out_vf);
2159        atomisp_flush_params_queue(&asd->video_out_preview);
2160        atomisp_flush_params_queue(&asd->video_out_video_capture);
2161        atomisp_free_css_parameters(&asd->params.css_param);
2162        memset(&asd->params.css_param, 0, sizeof(asd->params.css_param));
2163}
2164
2165void atomisp_css_continuous_set_num_raw_frames(
2166     struct atomisp_sub_device *asd,
2167     int num_frames)
2168{
2169        if (asd->enable_raw_buffer_lock->val) {
2170                asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2171                .stream_config.init_num_cont_raw_buf =
2172                    ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES_LOCK_EN;
2173                if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
2174                    asd->params.video_dis_en)
2175                        asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2176                        .stream_config.init_num_cont_raw_buf +=
2177                            ATOMISP_CSS2_NUM_DVS_FRAME_DELAY;
2178        } else {
2179                asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2180                .stream_config.init_num_cont_raw_buf =
2181                    ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES;
2182        }
2183
2184        if (asd->params.video_dis_en)
2185                asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2186                .stream_config.init_num_cont_raw_buf +=
2187                    ATOMISP_CSS2_NUM_DVS_FRAME_DELAY;
2188
2189        asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2190        .stream_config.target_num_cont_raw_buf = num_frames;
2191}
2192
2193static enum ia_css_pipe_mode __pipe_id_to_pipe_mode(
2194    struct atomisp_sub_device *asd,
2195    enum ia_css_pipe_id pipe_id)
2196{
2197        struct atomisp_device *isp = asd->isp;
2198        struct camera_mipi_info *mipi_info = atomisp_to_sensor_mipi_info(
2199                isp->inputs[asd->input_curr].camera);
2200
2201        switch (pipe_id) {
2202        case IA_CSS_PIPE_ID_COPY:
2203                /* Currently only YUVPP mode supports YUV420_Legacy format.
2204                 * Revert this when other pipe modes can support
2205                 * YUV420_Legacy format.
2206                 */
2207                if (mipi_info && mipi_info->input_format ==
2208                    ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY)
2209                        return IA_CSS_PIPE_MODE_YUVPP;
2210                return IA_CSS_PIPE_MODE_COPY;
2211        case IA_CSS_PIPE_ID_PREVIEW:
2212                return IA_CSS_PIPE_MODE_PREVIEW;
2213        case IA_CSS_PIPE_ID_CAPTURE:
2214                return IA_CSS_PIPE_MODE_CAPTURE;
2215        case IA_CSS_PIPE_ID_VIDEO:
2216                return IA_CSS_PIPE_MODE_VIDEO;
2217        case IA_CSS_PIPE_ID_ACC:
2218                return IA_CSS_PIPE_MODE_ACC;
2219        case IA_CSS_PIPE_ID_YUVPP:
2220                return IA_CSS_PIPE_MODE_YUVPP;
2221        default:
2222                WARN_ON(1);
2223                return IA_CSS_PIPE_MODE_PREVIEW;
2224        }
2225}
2226
2227static void __configure_output(struct atomisp_sub_device *asd,
2228                               unsigned int stream_index,
2229                               unsigned int width, unsigned int height,
2230                               unsigned int min_width,
2231                               enum ia_css_frame_format format,
2232                               enum ia_css_pipe_id pipe_id)
2233{
2234        struct atomisp_device *isp = asd->isp;
2235        struct atomisp_stream_env *stream_env =
2236                    &asd->stream_env[stream_index];
2237        struct ia_css_stream_config *s_config = &stream_env->stream_config;
2238
2239        stream_env->pipe_configs[pipe_id].mode =
2240            __pipe_id_to_pipe_mode(asd, pipe_id);
2241        stream_env->update_pipe[pipe_id] = true;
2242
2243        stream_env->pipe_configs[pipe_id].output_info[0].res.width = width;
2244        stream_env->pipe_configs[pipe_id].output_info[0].res.height = height;
2245        stream_env->pipe_configs[pipe_id].output_info[0].format = format;
2246        stream_env->pipe_configs[pipe_id].output_info[0].padded_width = min_width;
2247
2248        /* isp binary 2.2 specific setting*/
2249        if (width > s_config->input_config.effective_res.width ||
2250            height > s_config->input_config.effective_res.height) {
2251                s_config->input_config.effective_res.width = width;
2252                s_config->input_config.effective_res.height = height;
2253        }
2254
2255        dev_dbg(isp->dev, "configuring pipe[%d] output info w=%d.h=%d.f=%d.\n",
2256                pipe_id, width, height, format);
2257}
2258
2259static void __configure_video_preview_output(struct atomisp_sub_device *asd,
2260        unsigned int stream_index,
2261        unsigned int width, unsigned int height,
2262        unsigned int min_width,
2263        enum ia_css_frame_format format,
2264        enum ia_css_pipe_id pipe_id)
2265{
2266        struct atomisp_device *isp = asd->isp;
2267        struct atomisp_stream_env *stream_env =
2268                    &asd->stream_env[stream_index];
2269        struct ia_css_frame_info *css_output_info;
2270        struct ia_css_stream_config *stream_config = &stream_env->stream_config;
2271
2272        stream_env->pipe_configs[pipe_id].mode =
2273            __pipe_id_to_pipe_mode(asd, pipe_id);
2274        stream_env->update_pipe[pipe_id] = true;
2275
2276        /*
2277         * second_output will be as video main output in SDV mode
2278         * with SOC camera. output will be as video main output in
2279         * normal video mode.
2280         */
2281        if (asd->continuous_mode->val)
2282                css_output_info = &stream_env->pipe_configs[pipe_id].
2283                                  output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX];
2284        else
2285                css_output_info = &stream_env->pipe_configs[pipe_id].
2286                                  output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX];
2287
2288        css_output_info->res.width = width;
2289        css_output_info->res.height = height;
2290        css_output_info->format = format;
2291        css_output_info->padded_width = min_width;
2292
2293        /* isp binary 2.2 specific setting*/
2294        if (width > stream_config->input_config.effective_res.width ||
2295            height > stream_config->input_config.effective_res.height) {
2296                stream_config->input_config.effective_res.width = width;
2297                stream_config->input_config.effective_res.height = height;
2298        }
2299
2300        dev_dbg(isp->dev, "configuring pipe[%d] output info w=%d.h=%d.f=%d.\n",
2301                pipe_id, width, height, format);
2302}
2303
2304/*
2305 * For CSS2.1, capture pipe uses capture_pp_in_res to configure yuv
2306 * downscaling input resolution.
2307 */
2308static void __configure_capture_pp_input(struct atomisp_sub_device *asd,
2309        unsigned int width, unsigned int height,
2310        enum ia_css_pipe_id pipe_id)
2311{
2312        struct atomisp_device *isp = asd->isp;
2313        struct atomisp_stream_env *stream_env =
2314                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2315        struct ia_css_stream_config *stream_config = &stream_env->stream_config;
2316        struct ia_css_pipe_config *pipe_configs =
2317                    &stream_env->pipe_configs[pipe_id];
2318        struct ia_css_pipe_extra_config *pipe_extra_configs =
2319                    &stream_env->pipe_extra_configs[pipe_id];
2320        unsigned int hor_ds_factor = 0, ver_ds_factor = 0;
2321
2322        if (width == 0 && height == 0)
2323                return;
2324
2325        if (width * 9 / 10 < pipe_configs->output_info[0].res.width ||
2326            height * 9 / 10 < pipe_configs->output_info[0].res.height)
2327                return;
2328        /* here just copy the calculation in css */
2329        hor_ds_factor = CEIL_DIV(width >> 1,
2330                                 pipe_configs->output_info[0].res.width);
2331        ver_ds_factor = CEIL_DIV(height >> 1,
2332                                 pipe_configs->output_info[0].res.height);
2333
2334        if ((asd->isp->media_dev.hw_revision <
2335             (ATOMISP_HW_REVISION_ISP2401 << ATOMISP_HW_REVISION_SHIFT) ||
2336             IS_CHT) && hor_ds_factor != ver_ds_factor) {
2337                dev_warn(asd->isp->dev,
2338                         "Cropping for capture due to FW limitation");
2339                return;
2340        }
2341
2342        pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id);
2343        stream_env->update_pipe[pipe_id] = true;
2344
2345        pipe_extra_configs->enable_yuv_ds = true;
2346
2347        pipe_configs->capt_pp_in_res.width =
2348            stream_config->input_config.effective_res.width;
2349        pipe_configs->capt_pp_in_res.height =
2350            stream_config->input_config.effective_res.height;
2351
2352        dev_dbg(isp->dev, "configuring pipe[%d]capture pp input w=%d.h=%d.\n",
2353                pipe_id, width, height);
2354}
2355
2356/*
2357 * For CSS2.1, preview pipe could support bayer downscaling, yuv decimation and
2358 * yuv downscaling, which needs addtional configurations.
2359 */
2360static void __configure_preview_pp_input(struct atomisp_sub_device *asd,
2361        unsigned int width, unsigned int height,
2362        enum ia_css_pipe_id pipe_id)
2363{
2364        struct atomisp_device *isp = asd->isp;
2365        int out_width, out_height, yuv_ds_in_width, yuv_ds_in_height;
2366        struct atomisp_stream_env *stream_env =
2367                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2368        struct ia_css_stream_config *stream_config = &stream_env->stream_config;
2369        struct ia_css_pipe_config *pipe_configs =
2370                    &stream_env->pipe_configs[pipe_id];
2371        struct ia_css_pipe_extra_config *pipe_extra_configs =
2372                    &stream_env->pipe_extra_configs[pipe_id];
2373        struct ia_css_resolution *bayer_ds_out_res =
2374                    &pipe_configs->bayer_ds_out_res;
2375        struct ia_css_resolution *vf_pp_in_res =
2376                    &pipe_configs->vf_pp_in_res;
2377        struct ia_css_resolution  *effective_res =
2378                    &stream_config->input_config.effective_res;
2379
2380        static const struct bayer_ds_factor bds_fct[] = {{2, 1}, {3, 2}, {5, 4} };
2381        /*
2382         * BZ201033: YUV decimation factor of 4 causes couple of rightmost
2383         * columns to be shaded. Remove this factor to work around the CSS bug.
2384         * const unsigned int yuv_dec_fct[] = {4, 2};
2385         */
2386        static const unsigned int yuv_dec_fct[] = { 2 };
2387        unsigned int i;
2388
2389        if (width == 0 && height == 0)
2390                return;
2391
2392        pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id);
2393        stream_env->update_pipe[pipe_id] = true;
2394
2395        out_width = pipe_configs->output_info[0].res.width;
2396        out_height = pipe_configs->output_info[0].res.height;
2397
2398        /*
2399         * The ISP could do bayer downscaling, yuv decimation and yuv
2400         * downscaling:
2401         * 1: Bayer Downscaling: between effective resolution and
2402         * bayer_ds_res_out;
2403         * 2: YUV Decimation: between bayer_ds_res_out and vf_pp_in_res;
2404         * 3: YUV Downscaling: between vf_pp_in_res and final vf output
2405         *
2406         * Rule for Bayer Downscaling: support factor 2, 1.5 and 1.25
2407         * Rule for YUV Decimation: support factor 2, 4
2408         * Rule for YUV Downscaling: arbitrary value below 2
2409         *
2410         * General rule of factor distribution among these stages:
2411         * 1: try to do Bayer downscaling first if not in online mode.
2412         * 2: try to do maximum of 2 for YUV downscaling
2413         * 3: the remainling for YUV decimation
2414         *
2415         * Note:
2416         * Do not configure bayer_ds_out_res if:
2417         * online == 1 or continuous == 0 or raw_binning = 0
2418         */
2419        if (stream_config->online || !stream_config->continuous ||
2420            !pipe_extra_configs->enable_raw_binning) {
2421                bayer_ds_out_res->width = 0;
2422                bayer_ds_out_res->height = 0;
2423        } else {
2424                bayer_ds_out_res->width = effective_res->width;
2425                bayer_ds_out_res->height = effective_res->height;
2426
2427                for (i = 0; i < ARRAY_SIZE(bds_fct); i++) {
2428                        if (effective_res->width >= out_width *
2429                            bds_fct[i].numerator / bds_fct[i].denominator &&
2430                            effective_res->height >= out_height *
2431                            bds_fct[i].numerator / bds_fct[i].denominator) {
2432                                bayer_ds_out_res->width =
2433                                    effective_res->width *
2434                                    bds_fct[i].denominator /
2435                                    bds_fct[i].numerator;
2436                                bayer_ds_out_res->height =
2437                                    effective_res->height *
2438                                    bds_fct[i].denominator /
2439                                    bds_fct[i].numerator;
2440                                break;
2441                        }
2442                }
2443        }
2444        /*
2445         * calculate YUV Decimation, YUV downscaling facor:
2446         * YUV Downscaling factor must not exceed 2.
2447         * YUV Decimation factor could be 2, 4.
2448         */
2449        /* first decide the yuv_ds input resolution */
2450        if (bayer_ds_out_res->width == 0) {
2451                yuv_ds_in_width = effective_res->width;
2452                yuv_ds_in_height = effective_res->height;
2453        } else {
2454                yuv_ds_in_width = bayer_ds_out_res->width;
2455                yuv_ds_in_height = bayer_ds_out_res->height;
2456        }
2457
2458        vf_pp_in_res->width = yuv_ds_in_width;
2459        vf_pp_in_res->height = yuv_ds_in_height;
2460
2461        /* find out the yuv decimation factor */
2462        for (i = 0; i < ARRAY_SIZE(yuv_dec_fct); i++) {
2463                if (yuv_ds_in_width >= out_width * yuv_dec_fct[i] &&
2464                    yuv_ds_in_height >= out_height * yuv_dec_fct[i]) {
2465                        vf_pp_in_res->width = yuv_ds_in_width / yuv_dec_fct[i];
2466                        vf_pp_in_res->height = yuv_ds_in_height / yuv_dec_fct[i];
2467                        break;
2468                }
2469        }
2470
2471        if (vf_pp_in_res->width == out_width &&
2472            vf_pp_in_res->height == out_height) {
2473                pipe_extra_configs->enable_yuv_ds = false;
2474                vf_pp_in_res->width = 0;
2475                vf_pp_in_res->height = 0;
2476        } else {
2477                pipe_extra_configs->enable_yuv_ds = true;
2478        }
2479
2480        dev_dbg(isp->dev, "configuring pipe[%d]preview pp input w=%d.h=%d.\n",
2481                pipe_id, width, height);
2482}
2483
2484/*
2485 * For CSS2.1, offline video pipe could support bayer decimation, and
2486 * yuv downscaling, which needs addtional configurations.
2487 */
2488static void __configure_video_pp_input(struct atomisp_sub_device *asd,
2489                                       unsigned int width, unsigned int height,
2490                                       enum ia_css_pipe_id pipe_id)
2491{
2492        struct atomisp_device *isp = asd->isp;
2493        int out_width, out_height;
2494        struct atomisp_stream_env *stream_env =
2495                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2496        struct ia_css_stream_config *stream_config = &stream_env->stream_config;
2497        struct ia_css_pipe_config *pipe_configs =
2498                    &stream_env->pipe_configs[pipe_id];
2499        struct ia_css_pipe_extra_config *pipe_extra_configs =
2500                    &stream_env->pipe_extra_configs[pipe_id];
2501        struct ia_css_resolution *bayer_ds_out_res =
2502                    &pipe_configs->bayer_ds_out_res;
2503        struct ia_css_resolution  *effective_res =
2504                    &stream_config->input_config.effective_res;
2505
2506        static const struct bayer_ds_factor bds_factors[] = {
2507                {8, 1}, {6, 1}, {4, 1}, {3, 1}, {2, 1}, {3, 2}
2508        };
2509        unsigned int i;
2510
2511        if (width == 0 && height == 0)
2512                return;
2513
2514        pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id);
2515        stream_env->update_pipe[pipe_id] = true;
2516
2517        pipe_extra_configs->enable_yuv_ds = false;
2518
2519        /*
2520         * If DVS is enabled,  video binary will take care the dvs envelope
2521         * and usually the bayer_ds_out_res should be larger than 120% of
2522         * destination resolution, the extra 20% will be cropped as DVS
2523         * envelope. But,  if the bayer_ds_out_res is less than 120% of the
2524         * destination. The ISP can still work,  but DVS quality is not good.
2525         */
2526        /* taking at least 10% as envelope */
2527        if (asd->params.video_dis_en) {
2528                out_width = pipe_configs->output_info[0].res.width * 110 / 100;
2529                out_height = pipe_configs->output_info[0].res.height * 110 / 100;
2530        } else {
2531                out_width = pipe_configs->output_info[0].res.width;
2532                out_height = pipe_configs->output_info[0].res.height;
2533        }
2534
2535        /*
2536         * calculate bayer decimate factor:
2537         * 1: only 1.5, 2, 4 and 8 get supported
2538         * 2: Do not configure bayer_ds_out_res if:
2539         *    online == 1 or continuous == 0 or raw_binning = 0
2540         */
2541        if (stream_config->online || !stream_config->continuous) {
2542                bayer_ds_out_res->width = 0;
2543                bayer_ds_out_res->height = 0;
2544                goto done;
2545        }
2546
2547        pipe_extra_configs->enable_raw_binning = true;
2548        bayer_ds_out_res->width = effective_res->width;
2549        bayer_ds_out_res->height = effective_res->height;
2550
2551        for (i = 0; i < sizeof(bds_factors) / sizeof(struct bayer_ds_factor);
2552             i++) {
2553                if (effective_res->width >= out_width *
2554                    bds_factors[i].numerator / bds_factors[i].denominator &&
2555                    effective_res->height >= out_height *
2556                    bds_factors[i].numerator / bds_factors[i].denominator) {
2557                        bayer_ds_out_res->width = effective_res->width *
2558                                                  bds_factors[i].denominator /
2559                                                  bds_factors[i].numerator;
2560                        bayer_ds_out_res->height = effective_res->height *
2561                                                   bds_factors[i].denominator /
2562                                                   bds_factors[i].numerator;
2563                        break;
2564                }
2565        }
2566
2567        /*
2568         * DVS is cropped from BDS output, so we do not really need to set the
2569         * envelope to 20% of output resolution here. always set it to 12x12
2570         * per firmware requirement.
2571         */
2572        pipe_configs->dvs_envelope.width = 12;
2573        pipe_configs->dvs_envelope.height = 12;
2574
2575done:
2576        if (pipe_id == IA_CSS_PIPE_ID_YUVPP)
2577                stream_config->left_padding = -1;
2578        else
2579                stream_config->left_padding = 12;
2580        dev_dbg(isp->dev, "configuring pipe[%d]video pp input w=%d.h=%d.\n",
2581                pipe_id, width, height);
2582}
2583
2584static void __configure_vf_output(struct atomisp_sub_device *asd,
2585                                  unsigned int width, unsigned int height,
2586                                  unsigned int min_width,
2587                                  enum ia_css_frame_format format,
2588                                  enum ia_css_pipe_id pipe_id)
2589{
2590        struct atomisp_device *isp = asd->isp;
2591        struct atomisp_stream_env *stream_env =
2592                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2593        stream_env->pipe_configs[pipe_id].mode =
2594            __pipe_id_to_pipe_mode(asd, pipe_id);
2595        stream_env->update_pipe[pipe_id] = true;
2596
2597        stream_env->pipe_configs[pipe_id].vf_output_info[0].res.width = width;
2598        stream_env->pipe_configs[pipe_id].vf_output_info[0].res.height = height;
2599        stream_env->pipe_configs[pipe_id].vf_output_info[0].format = format;
2600        stream_env->pipe_configs[pipe_id].vf_output_info[0].padded_width =
2601            min_width;
2602        dev_dbg(isp->dev,
2603                "configuring pipe[%d] vf output info w=%d.h=%d.f=%d.\n",
2604                pipe_id, width, height, format);
2605}
2606
2607static void __configure_video_vf_output(struct atomisp_sub_device *asd,
2608                                        unsigned int width, unsigned int height,
2609                                        unsigned int min_width,
2610                                        enum ia_css_frame_format format,
2611                                        enum ia_css_pipe_id pipe_id)
2612{
2613        struct atomisp_device *isp = asd->isp;
2614        struct atomisp_stream_env *stream_env =
2615                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2616        struct ia_css_frame_info *css_output_info;
2617
2618        stream_env->pipe_configs[pipe_id].mode =
2619            __pipe_id_to_pipe_mode(asd, pipe_id);
2620        stream_env->update_pipe[pipe_id] = true;
2621
2622        /*
2623         * second_vf_output will be as video viewfinder in SDV mode
2624         * with SOC camera. vf_output will be as video viewfinder in
2625         * normal video mode.
2626         */
2627        if (asd->continuous_mode->val)
2628                css_output_info = &stream_env->pipe_configs[pipe_id].
2629                                  vf_output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX];
2630        else
2631                css_output_info = &stream_env->pipe_configs[pipe_id].
2632                                  vf_output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX];
2633
2634        css_output_info->res.width = width;
2635        css_output_info->res.height = height;
2636        css_output_info->format = format;
2637        css_output_info->padded_width = min_width;
2638        dev_dbg(isp->dev,
2639                "configuring pipe[%d] vf output info w=%d.h=%d.f=%d.\n",
2640                pipe_id, width, height, format);
2641}
2642
2643static int __get_frame_info(struct atomisp_sub_device *asd,
2644                            unsigned int stream_index,
2645                            struct ia_css_frame_info *info,
2646                            enum frame_info_type type,
2647                            enum ia_css_pipe_id pipe_id)
2648{
2649        struct atomisp_device *isp = asd->isp;
2650        int ret;
2651        struct ia_css_pipe_info p_info;
2652
2653        /* FIXME! No need to destroy/recreate all streams */
2654        if (__destroy_streams(asd, true))
2655                dev_warn(isp->dev, "destroy stream failed.\n");
2656
2657        if (__destroy_pipes(asd, true))
2658                dev_warn(isp->dev, "destroy pipe failed.\n");
2659
2660        if (__create_pipes(asd))
2661                return -EINVAL;
2662
2663        if (__create_streams(asd))
2664                goto stream_err;
2665
2666        ret = ia_css_pipe_get_info(
2667                  asd->stream_env[stream_index]
2668                  .pipes[pipe_id], &p_info);
2669        if (!ret) {
2670                switch (type) {
2671                case ATOMISP_CSS_VF_FRAME:
2672                        *info = p_info.vf_output_info[0];
2673                        dev_dbg(isp->dev, "getting vf frame info.\n");
2674                        break;
2675                case ATOMISP_CSS_SECOND_VF_FRAME:
2676                        *info = p_info.vf_output_info[1];
2677                        dev_dbg(isp->dev, "getting second vf frame info.\n");
2678                        break;
2679                case ATOMISP_CSS_OUTPUT_FRAME:
2680                        *info = p_info.output_info[0];
2681                        dev_dbg(isp->dev, "getting main frame info.\n");
2682                        break;
2683                case ATOMISP_CSS_SECOND_OUTPUT_FRAME:
2684                        *info = p_info.output_info[1];
2685                        dev_dbg(isp->dev, "getting second main frame info.\n");
2686                        break;
2687                case ATOMISP_CSS_RAW_FRAME:
2688                        *info = p_info.raw_output_info;
2689                        dev_dbg(isp->dev, "getting raw frame info.\n");
2690                }
2691                dev_dbg(isp->dev, "get frame info: w=%d, h=%d, num_invalid_frames %d.\n",
2692                        info->res.width, info->res.height, p_info.num_invalid_frames);
2693                return 0;
2694        }
2695
2696stream_err:
2697        __destroy_pipes(asd, true);
2698        return -EINVAL;
2699}
2700
2701static unsigned int atomisp_get_pipe_index(struct atomisp_sub_device *asd,
2702        uint16_t source_pad)
2703{
2704        struct atomisp_device *isp = asd->isp;
2705        /*
2706         * to SOC camera, use yuvpp pipe.
2707         */
2708        if (ATOMISP_USE_YUVPP(asd))
2709                return IA_CSS_PIPE_ID_YUVPP;
2710
2711        switch (source_pad) {
2712        case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO:
2713                if (asd->yuvpp_mode)
2714                        return IA_CSS_PIPE_ID_YUVPP;
2715                if (asd->copy_mode)
2716                        return IA_CSS_PIPE_ID_COPY;
2717                if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO
2718                    || asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER)
2719                        return IA_CSS_PIPE_ID_VIDEO;
2720
2721                return IA_CSS_PIPE_ID_CAPTURE;
2722        case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
2723                if (asd->copy_mode)
2724                        return IA_CSS_PIPE_ID_COPY;
2725
2726                return IA_CSS_PIPE_ID_CAPTURE;
2727        case ATOMISP_SUBDEV_PAD_SOURCE_VF:
2728                if (!atomisp_is_mbuscode_raw(asd->fmt[asd->capture_pad].fmt.code)) {
2729                        return IA_CSS_PIPE_ID_CAPTURE;
2730                }
2731                fallthrough;
2732        case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
2733                if (asd->yuvpp_mode)
2734                        return IA_CSS_PIPE_ID_YUVPP;
2735                if (asd->copy_mode)
2736                        return IA_CSS_PIPE_ID_COPY;
2737                if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
2738                        return IA_CSS_PIPE_ID_VIDEO;
2739
2740                return IA_CSS_PIPE_ID_PREVIEW;
2741        }
2742        dev_warn(isp->dev,
2743                 "invalid source pad:%d, return default preview pipe index.\n",
2744                 source_pad);
2745        return IA_CSS_PIPE_ID_PREVIEW;
2746}
2747
2748int atomisp_get_css_frame_info(struct atomisp_sub_device *asd,
2749                               u16 source_pad,
2750                               struct ia_css_frame_info *frame_info)
2751{
2752        struct ia_css_pipe_info info;
2753        int pipe_index = atomisp_get_pipe_index(asd, source_pad);
2754        int stream_index;
2755        struct atomisp_device *isp = asd->isp;
2756
2757        if (ATOMISP_SOC_CAMERA(asd)) {
2758                stream_index = atomisp_source_pad_to_stream_id(asd, source_pad);
2759        } else {
2760                stream_index = (pipe_index == IA_CSS_PIPE_ID_YUVPP) ?
2761                               ATOMISP_INPUT_STREAM_VIDEO :
2762                               atomisp_source_pad_to_stream_id(asd, source_pad);
2763        }
2764
2765        if (0 != ia_css_pipe_get_info(asd->stream_env[stream_index]
2766                .pipes[pipe_index], &info)) {
2767                dev_err(isp->dev, "ia_css_pipe_get_info FAILED");
2768                return -EINVAL;
2769        }
2770
2771        switch (source_pad) {
2772        case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
2773                *frame_info = info.output_info[0];
2774                break;
2775        case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO:
2776                if (ATOMISP_USE_YUVPP(asd) && asd->continuous_mode->val)
2777                        *frame_info = info.
2778                                      output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX];
2779                else
2780                        *frame_info = info.
2781                                      output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX];
2782                break;
2783        case ATOMISP_SUBDEV_PAD_SOURCE_VF:
2784                if (stream_index == ATOMISP_INPUT_STREAM_POSTVIEW)
2785                        *frame_info = info.output_info[0];
2786                else
2787                        *frame_info = info.vf_output_info[0];
2788                break;
2789        case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
2790                if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
2791                    (pipe_index == IA_CSS_PIPE_ID_VIDEO ||
2792                     pipe_index == IA_CSS_PIPE_ID_YUVPP))
2793                        if (ATOMISP_USE_YUVPP(asd) && asd->continuous_mode->val)
2794                                *frame_info = info.
2795                                              vf_output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX];
2796                        else
2797                                *frame_info = info.
2798                                              vf_output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX];
2799                else if (ATOMISP_USE_YUVPP(asd) && asd->continuous_mode->val)
2800                        *frame_info =
2801                            info.output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX];
2802                else
2803                        *frame_info =
2804                            info.output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX];
2805
2806                break;
2807        default:
2808                frame_info = NULL;
2809                break;
2810        }
2811        return frame_info ? 0 : -EINVAL;
2812}
2813
2814int atomisp_css_copy_configure_output(struct atomisp_sub_device *asd,
2815                                      unsigned int stream_index,
2816                                      unsigned int width, unsigned int height,
2817                                      unsigned int padded_width,
2818                                      enum ia_css_frame_format format)
2819{
2820        asd->stream_env[stream_index].pipe_configs[IA_CSS_PIPE_ID_COPY].
2821        default_capture_config.mode =
2822            IA_CSS_CAPTURE_MODE_RAW;
2823
2824        __configure_output(asd, stream_index, width, height, padded_width,
2825                           format, IA_CSS_PIPE_ID_COPY);
2826        return 0;
2827}
2828
2829int atomisp_css_yuvpp_configure_output(struct atomisp_sub_device *asd,
2830                                       unsigned int stream_index,
2831                                       unsigned int width, unsigned int height,
2832                                       unsigned int padded_width,
2833                                       enum ia_css_frame_format format)
2834{
2835        asd->stream_env[stream_index].pipe_configs[IA_CSS_PIPE_ID_YUVPP].
2836        default_capture_config.mode =
2837            IA_CSS_CAPTURE_MODE_RAW;
2838
2839        __configure_output(asd, stream_index, width, height, padded_width,
2840                           format, IA_CSS_PIPE_ID_YUVPP);
2841        return 0;
2842}
2843
2844int atomisp_css_yuvpp_configure_viewfinder(
2845    struct atomisp_sub_device *asd,
2846    unsigned int stream_index,
2847    unsigned int width, unsigned int height,
2848    unsigned int min_width,
2849    enum ia_css_frame_format format)
2850{
2851        struct atomisp_stream_env *stream_env =
2852                    &asd->stream_env[stream_index];
2853        enum ia_css_pipe_id pipe_id = IA_CSS_PIPE_ID_YUVPP;
2854
2855        stream_env->pipe_configs[pipe_id].mode =
2856            __pipe_id_to_pipe_mode(asd, pipe_id);
2857        stream_env->update_pipe[pipe_id] = true;
2858
2859        stream_env->pipe_configs[pipe_id].vf_output_info[0].res.width = width;
2860        stream_env->pipe_configs[pipe_id].vf_output_info[0].res.height = height;
2861        stream_env->pipe_configs[pipe_id].vf_output_info[0].format = format;
2862        stream_env->pipe_configs[pipe_id].vf_output_info[0].padded_width =
2863            min_width;
2864        return 0;
2865}
2866
2867int atomisp_css_yuvpp_get_output_frame_info(
2868    struct atomisp_sub_device *asd,
2869    unsigned int stream_index,
2870    struct ia_css_frame_info *info)
2871{
2872        return __get_frame_info(asd, stream_index, info,
2873                                ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_YUVPP);
2874}
2875
2876int atomisp_css_yuvpp_get_viewfinder_frame_info(
2877    struct atomisp_sub_device *asd,
2878    unsigned int stream_index,
2879    struct ia_css_frame_info *info)
2880{
2881        return __get_frame_info(asd, stream_index, info,
2882                                ATOMISP_CSS_VF_FRAME, IA_CSS_PIPE_ID_YUVPP);
2883}
2884
2885int atomisp_css_preview_configure_output(struct atomisp_sub_device *asd,
2886        unsigned int width, unsigned int height,
2887        unsigned int min_width,
2888        enum ia_css_frame_format format)
2889{
2890        /*
2891         * to SOC camera, use yuvpp pipe.
2892         */
2893        if (ATOMISP_USE_YUVPP(asd))
2894                __configure_video_preview_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width,
2895                                                 height,
2896                                                 min_width, format, IA_CSS_PIPE_ID_YUVPP);
2897        else
2898                __configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height,
2899                                   min_width, format, IA_CSS_PIPE_ID_PREVIEW);
2900        return 0;
2901}
2902
2903int atomisp_css_capture_configure_output(struct atomisp_sub_device *asd,
2904        unsigned int width, unsigned int height,
2905        unsigned int min_width,
2906        enum ia_css_frame_format format)
2907{
2908        enum ia_css_pipe_id pipe_id;
2909
2910        /*
2911         * to SOC camera, use yuvpp pipe.
2912         */
2913        if (ATOMISP_USE_YUVPP(asd))
2914                pipe_id = IA_CSS_PIPE_ID_YUVPP;
2915        else
2916                pipe_id = IA_CSS_PIPE_ID_CAPTURE;
2917
2918        __configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height,
2919                           min_width, format, pipe_id);
2920        return 0;
2921}
2922
2923int atomisp_css_video_configure_output(struct atomisp_sub_device *asd,
2924                                       unsigned int width, unsigned int height,
2925                                       unsigned int min_width,
2926                                       enum ia_css_frame_format format)
2927{
2928        /*
2929         * to SOC camera, use yuvpp pipe.
2930         */
2931        if (ATOMISP_USE_YUVPP(asd))
2932                __configure_video_preview_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width,
2933                                                 height,
2934                                                 min_width, format, IA_CSS_PIPE_ID_YUVPP);
2935        else
2936                __configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height,
2937                                   min_width, format, IA_CSS_PIPE_ID_VIDEO);
2938        return 0;
2939}
2940
2941int atomisp_css_video_configure_viewfinder(
2942    struct atomisp_sub_device *asd,
2943    unsigned int width, unsigned int height,
2944    unsigned int min_width,
2945    enum ia_css_frame_format format)
2946{
2947        /*
2948         * to SOC camera, video will use yuvpp pipe.
2949         */
2950        if (ATOMISP_USE_YUVPP(asd))
2951                __configure_video_vf_output(asd, width, height, min_width, format,
2952                                            IA_CSS_PIPE_ID_YUVPP);
2953        else
2954                __configure_vf_output(asd, width, height, min_width, format,
2955                                      IA_CSS_PIPE_ID_VIDEO);
2956        return 0;
2957}
2958
2959int atomisp_css_capture_configure_viewfinder(
2960    struct atomisp_sub_device *asd,
2961    unsigned int width, unsigned int height,
2962    unsigned int min_width,
2963    enum ia_css_frame_format format)
2964{
2965        enum ia_css_pipe_id pipe_id;
2966
2967        /*
2968         * to SOC camera, video will use yuvpp pipe.
2969         */
2970        if (ATOMISP_USE_YUVPP(asd))
2971                pipe_id = IA_CSS_PIPE_ID_YUVPP;
2972        else
2973                pipe_id = IA_CSS_PIPE_ID_CAPTURE;
2974
2975        __configure_vf_output(asd, width, height, min_width, format,
2976                              pipe_id);
2977        return 0;
2978}
2979
2980int atomisp_css_video_get_viewfinder_frame_info(
2981    struct atomisp_sub_device *asd,
2982    struct ia_css_frame_info *info)
2983{
2984        enum ia_css_pipe_id pipe_id;
2985        enum frame_info_type frame_type = ATOMISP_CSS_VF_FRAME;
2986
2987        if (ATOMISP_USE_YUVPP(asd)) {
2988                pipe_id = IA_CSS_PIPE_ID_YUVPP;
2989                if (asd->continuous_mode->val)
2990                        frame_type = ATOMISP_CSS_SECOND_VF_FRAME;
2991        } else {
2992                pipe_id = IA_CSS_PIPE_ID_VIDEO;
2993        }
2994
2995        return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
2996                                frame_type, pipe_id);
2997}
2998
2999int atomisp_css_capture_get_viewfinder_frame_info(
3000    struct atomisp_sub_device *asd,
3001    struct ia_css_frame_info *info)
3002{
3003        enum ia_css_pipe_id pipe_id;
3004
3005        if (ATOMISP_USE_YUVPP(asd))
3006                pipe_id = IA_CSS_PIPE_ID_YUVPP;
3007        else
3008                pipe_id = IA_CSS_PIPE_ID_CAPTURE;
3009
3010        return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
3011                                ATOMISP_CSS_VF_FRAME, pipe_id);
3012}
3013
3014int atomisp_css_capture_get_output_raw_frame_info(
3015    struct atomisp_sub_device *asd,
3016    struct ia_css_frame_info *info)
3017{
3018        if (ATOMISP_USE_YUVPP(asd))
3019                return 0;
3020
3021        return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
3022                                ATOMISP_CSS_RAW_FRAME, IA_CSS_PIPE_ID_CAPTURE);
3023}
3024
3025int atomisp_css_copy_get_output_frame_info(
3026    struct atomisp_sub_device *asd,
3027    unsigned int stream_index,
3028    struct ia_css_frame_info *info)
3029{
3030        return __get_frame_info(asd, stream_index, info,
3031                                ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_COPY);
3032}
3033
3034int atomisp_css_preview_get_output_frame_info(
3035    struct atomisp_sub_device *asd,
3036    struct ia_css_frame_info *info)
3037{
3038        enum ia_css_pipe_id pipe_id;
3039        enum frame_info_type frame_type = ATOMISP_CSS_OUTPUT_FRAME;
3040
3041        if (ATOMISP_USE_YUVPP(asd)) {
3042                pipe_id = IA_CSS_PIPE_ID_YUVPP;
3043                if (asd->continuous_mode->val)
3044                        frame_type = ATOMISP_CSS_SECOND_OUTPUT_FRAME;
3045        } else {
3046                pipe_id = IA_CSS_PIPE_ID_PREVIEW;
3047        }
3048
3049        return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
3050                                frame_type, pipe_id);
3051}
3052
3053int atomisp_css_capture_get_output_frame_info(
3054    struct atomisp_sub_device *asd,
3055    struct ia_css_frame_info *info)
3056{
3057        enum ia_css_pipe_id pipe_id;
3058
3059        if (ATOMISP_USE_YUVPP(asd))
3060                pipe_id = IA_CSS_PIPE_ID_YUVPP;
3061        else
3062                pipe_id = IA_CSS_PIPE_ID_CAPTURE;
3063
3064        return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
3065                                ATOMISP_CSS_OUTPUT_FRAME, pipe_id);
3066}
3067
3068int atomisp_css_video_get_output_frame_info(
3069    struct atomisp_sub_device *asd,
3070    struct ia_css_frame_info *info)
3071{
3072        enum ia_css_pipe_id pipe_id;
3073        enum frame_info_type frame_type = ATOMISP_CSS_OUTPUT_FRAME;
3074
3075        if (ATOMISP_USE_YUVPP(asd)) {
3076                pipe_id = IA_CSS_PIPE_ID_YUVPP;
3077                if (asd->continuous_mode->val)
3078                        frame_type = ATOMISP_CSS_SECOND_OUTPUT_FRAME;
3079        } else {
3080                pipe_id = IA_CSS_PIPE_ID_VIDEO;
3081        }
3082
3083        return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
3084                                frame_type, pipe_id);
3085}
3086
3087int atomisp_css_preview_configure_pp_input(
3088    struct atomisp_sub_device *asd,
3089    unsigned int width, unsigned int height)
3090{
3091        struct atomisp_stream_env *stream_env =
3092                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
3093        __configure_preview_pp_input(asd, width, height,
3094                                     ATOMISP_USE_YUVPP(asd) ?
3095                                     IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_PREVIEW);
3096
3097        if (width > stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE].
3098            capt_pp_in_res.width)
3099                __configure_capture_pp_input(asd, width, height,
3100                                             ATOMISP_USE_YUVPP(asd) ?
3101                                             IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_CAPTURE);
3102        return 0;
3103}
3104
3105int atomisp_css_capture_configure_pp_input(
3106    struct atomisp_sub_device *asd,
3107    unsigned int width, unsigned int height)
3108{
3109        __configure_capture_pp_input(asd, width, height,
3110                                     ATOMISP_USE_YUVPP(asd) ?
3111                                     IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_CAPTURE);
3112        return 0;
3113}
3114
3115int atomisp_css_video_configure_pp_input(
3116    struct atomisp_sub_device *asd,
3117    unsigned int width, unsigned int height)
3118{
3119        struct atomisp_stream_env *stream_env =
3120                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
3121
3122        __configure_video_pp_input(asd, width, height,
3123                                   ATOMISP_USE_YUVPP(asd) ?
3124                                   IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_VIDEO);
3125
3126        if (width > stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE].
3127            capt_pp_in_res.width)
3128                __configure_capture_pp_input(asd, width, height,
3129                                             ATOMISP_USE_YUVPP(asd) ?
3130                                             IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_CAPTURE);
3131        return 0;
3132}
3133
3134int atomisp_css_offline_capture_configure(struct atomisp_sub_device *asd,
3135        int num_captures, unsigned int skip, int offset)
3136{
3137        int ret;
3138
3139        dev_dbg(asd->isp->dev, "%s num_capture:%d skip:%d offset:%d\n",
3140                __func__, num_captures, skip, offset);
3141
3142        ret = ia_css_stream_capture(
3143                  asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3144                  num_captures, skip, offset);
3145        if (ret)
3146                return -EINVAL;
3147
3148        return 0;
3149}
3150
3151int atomisp_css_exp_id_capture(struct atomisp_sub_device *asd, int exp_id)
3152{
3153        int ret;
3154
3155        ret = ia_css_stream_capture_frame(
3156                  asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3157                  exp_id);
3158        if (ret == -ENOBUFS) {
3159                /* capture cmd queue is full */
3160                return -EBUSY;
3161        } else if (ret) {
3162                return -EIO;
3163        }
3164
3165        return 0;
3166}
3167
3168int atomisp_css_exp_id_unlock(struct atomisp_sub_device *asd, int exp_id)
3169{
3170        int ret;
3171
3172        ret = ia_css_unlock_raw_frame(
3173                  asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3174                  exp_id);
3175        if (ret == -ENOBUFS)
3176                return -EAGAIN;
3177        else if (ret)
3178                return -EIO;
3179
3180        return 0;
3181}
3182
3183int atomisp_css_capture_enable_xnr(struct atomisp_sub_device *asd,
3184                                   bool enable)
3185{
3186        asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
3187        .pipe_configs[IA_CSS_PIPE_ID_CAPTURE]
3188        .default_capture_config.enable_xnr = enable;
3189        asd->params.capture_config.enable_xnr = enable;
3190        asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
3191        .update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true;
3192
3193        return 0;
3194}
3195
3196void atomisp_css_set_ctc_table(struct atomisp_sub_device *asd,
3197                               struct ia_css_ctc_table *ctc_table)
3198{
3199        int i;
3200        u16 *vamem_ptr = ctc_table->data.vamem_1;
3201        int data_size = IA_CSS_VAMEM_1_CTC_TABLE_SIZE;
3202        bool valid = false;
3203
3204        /* workaround: if ctc_table is all 0, do not apply it */
3205        if (ctc_table->vamem_type == IA_CSS_VAMEM_TYPE_2) {
3206                vamem_ptr = ctc_table->data.vamem_2;
3207                data_size = IA_CSS_VAMEM_2_CTC_TABLE_SIZE;
3208        }
3209
3210        for (i = 0; i < data_size; i++) {
3211                if (*(vamem_ptr + i)) {
3212                        valid = true;
3213                        break;
3214                }
3215        }
3216
3217        if (valid)
3218                asd->params.config.ctc_table = ctc_table;
3219        else
3220                dev_warn(asd->isp->dev, "Bypass the invalid ctc_table.\n");
3221}
3222
3223void atomisp_css_set_anr_thres(struct atomisp_sub_device *asd,
3224                               struct ia_css_anr_thres *anr_thres)
3225{
3226        asd->params.config.anr_thres = anr_thres;
3227}
3228
3229void atomisp_css_set_dvs_6axis(struct atomisp_sub_device *asd,
3230                               struct ia_css_dvs_6axis_config *dvs_6axis)
3231{
3232        asd->params.config.dvs_6axis_config = dvs_6axis;
3233}
3234
3235void atomisp_css_video_set_dis_vector(struct atomisp_sub_device *asd,
3236                                      struct atomisp_dis_vector *vector)
3237{
3238        if (!asd->params.config.motion_vector)
3239                asd->params.config.motion_vector = &asd->params.css_param.motion_vector;
3240
3241        memset(asd->params.config.motion_vector,
3242               0, sizeof(struct ia_css_vector));
3243        asd->params.css_param.motion_vector.x = vector->x;
3244        asd->params.css_param.motion_vector.y = vector->y;
3245}
3246
3247static int atomisp_compare_dvs_grid(struct atomisp_sub_device *asd,
3248                                    struct atomisp_dvs_grid_info *atomgrid)
3249{
3250        struct ia_css_dvs_grid_info *cur =
3251            atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
3252
3253        if (!cur) {
3254                dev_err(asd->isp->dev, "dvs grid not available!\n");
3255                return -EINVAL;
3256        }
3257
3258        if (sizeof(*cur) != sizeof(*atomgrid)) {
3259                dev_err(asd->isp->dev, "dvs grid mis-match!\n");
3260                return -EINVAL;
3261        }
3262
3263        if (!cur->enable) {
3264                dev_err(asd->isp->dev, "dvs not enabled!\n");
3265                return -EINVAL;
3266        }
3267
3268        return memcmp(atomgrid, cur, sizeof(*cur));
3269}
3270
3271void  atomisp_css_set_dvs2_coefs(struct atomisp_sub_device *asd,
3272                                 struct ia_css_dvs2_coefficients *coefs)
3273{
3274        asd->params.config.dvs2_coefs = coefs;
3275}
3276
3277int atomisp_css_set_dis_coefs(struct atomisp_sub_device *asd,
3278                              struct atomisp_dis_coefficients *coefs)
3279{
3280        if (atomisp_compare_dvs_grid(asd, &coefs->grid_info) != 0)
3281                /* If the grid info in the argument differs from the current
3282                   grid info, we tell the caller to reset the grid size and
3283                   try again. */
3284                return -EAGAIN;
3285
3286        if (!coefs->hor_coefs.odd_real ||
3287            !coefs->hor_coefs.odd_imag ||
3288            !coefs->hor_coefs.even_real ||
3289            !coefs->hor_coefs.even_imag ||
3290            !coefs->ver_coefs.odd_real ||
3291            !coefs->ver_coefs.odd_imag ||
3292            !coefs->ver_coefs.even_real ||
3293            !coefs->ver_coefs.even_imag ||
3294            !asd->params.css_param.dvs2_coeff->hor_coefs.odd_real ||
3295            !asd->params.css_param.dvs2_coeff->hor_coefs.odd_imag ||
3296            !asd->params.css_param.dvs2_coeff->hor_coefs.even_real ||
3297            !asd->params.css_param.dvs2_coeff->hor_coefs.even_imag ||
3298            !asd->params.css_param.dvs2_coeff->ver_coefs.odd_real ||
3299            !asd->params.css_param.dvs2_coeff->ver_coefs.odd_imag ||
3300            !asd->params.css_param.dvs2_coeff->ver_coefs.even_real ||
3301            !asd->params.css_param.dvs2_coeff->ver_coefs.even_imag)
3302                return -EINVAL;
3303
3304        if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.odd_real,
3305                           coefs->hor_coefs.odd_real, asd->params.dvs_hor_coef_bytes))
3306                return -EFAULT;
3307        if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.odd_imag,
3308                           coefs->hor_coefs.odd_imag, asd->params.dvs_hor_coef_bytes))
3309                return -EFAULT;
3310        if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.even_real,
3311                           coefs->hor_coefs.even_real, asd->params.dvs_hor_coef_bytes))
3312                return -EFAULT;
3313        if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.even_imag,
3314                           coefs->hor_coefs.even_imag, asd->params.dvs_hor_coef_bytes))
3315                return -EFAULT;
3316
3317        if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.odd_real,
3318                           coefs->ver_coefs.odd_real, asd->params.dvs_ver_coef_bytes))
3319                return -EFAULT;
3320        if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.odd_imag,
3321                           coefs->ver_coefs.odd_imag, asd->params.dvs_ver_coef_bytes))
3322                return -EFAULT;
3323        if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.even_real,
3324                           coefs->ver_coefs.even_real, asd->params.dvs_ver_coef_bytes))
3325                return -EFAULT;
3326        if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.even_imag,
3327                           coefs->ver_coefs.even_imag, asd->params.dvs_ver_coef_bytes))
3328                return -EFAULT;
3329
3330        asd->params.css_param.update_flag.dvs2_coefs =
3331                (struct atomisp_dis_coefficients *)
3332                asd->params.css_param.dvs2_coeff;
3333        /* FIXME! */
3334        /*      asd->params.dis_proj_data_valid = false; */
3335        asd->params.css_update_params_needed = true;
3336
3337        return 0;
3338}
3339
3340void atomisp_css_set_zoom_factor(struct atomisp_sub_device *asd,
3341                                 unsigned int zoom)
3342{
3343        struct atomisp_device *isp = asd->isp;
3344
3345        if (zoom == asd->params.css_param.dz_config.dx &&
3346            zoom == asd->params.css_param.dz_config.dy) {
3347                dev_dbg(isp->dev, "same zoom scale. skipped.\n");
3348                return;
3349        }
3350
3351        memset(&asd->params.css_param.dz_config, 0,
3352               sizeof(struct ia_css_dz_config));
3353        asd->params.css_param.dz_config.dx = zoom;
3354        asd->params.css_param.dz_config.dy = zoom;
3355
3356        asd->params.css_param.update_flag.dz_config =
3357            (struct atomisp_dz_config *)&asd->params.css_param.dz_config;
3358        asd->params.css_update_params_needed = true;
3359}
3360
3361void atomisp_css_set_formats_config(struct atomisp_sub_device *asd,
3362                                    struct ia_css_formats_config *formats_config)
3363{
3364        asd->params.config.formats_config = formats_config;
3365}
3366
3367int atomisp_css_get_wb_config(struct atomisp_sub_device *asd,
3368                              struct atomisp_wb_config *config)
3369{
3370        struct ia_css_wb_config wb_config;
3371        struct ia_css_isp_config isp_config;
3372        struct atomisp_device *isp = asd->isp;
3373
3374        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3375                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3376                        __func__);
3377                return -EINVAL;
3378        }
3379        memset(&wb_config, 0, sizeof(struct ia_css_wb_config));
3380        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3381        isp_config.wb_config = &wb_config;
3382        ia_css_stream_get_isp_config(
3383            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3384            &isp_config);
3385        memcpy(config, &wb_config, sizeof(*config));
3386
3387        return 0;
3388}
3389
3390int atomisp_css_get_ob_config(struct atomisp_sub_device *asd,
3391                              struct atomisp_ob_config *config)
3392{
3393        struct ia_css_ob_config ob_config;
3394        struct ia_css_isp_config isp_config;
3395        struct atomisp_device *isp = asd->isp;
3396
3397        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3398                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3399                        __func__);
3400                return -EINVAL;
3401        }
3402        memset(&ob_config, 0, sizeof(struct ia_css_ob_config));
3403        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3404        isp_config.ob_config = &ob_config;
3405        ia_css_stream_get_isp_config(
3406            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3407            &isp_config);
3408        memcpy(config, &ob_config, sizeof(*config));
3409
3410        return 0;
3411}
3412
3413int atomisp_css_get_dp_config(struct atomisp_sub_device *asd,
3414                              struct atomisp_dp_config *config)
3415{
3416        struct ia_css_dp_config dp_config;
3417        struct ia_css_isp_config isp_config;
3418        struct atomisp_device *isp = asd->isp;
3419
3420        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3421                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3422                        __func__);
3423                return -EINVAL;
3424        }
3425        memset(&dp_config, 0, sizeof(struct ia_css_dp_config));
3426        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3427        isp_config.dp_config = &dp_config;
3428        ia_css_stream_get_isp_config(
3429            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3430            &isp_config);
3431        memcpy(config, &dp_config, sizeof(*config));
3432
3433        return 0;
3434}
3435
3436int atomisp_css_get_de_config(struct atomisp_sub_device *asd,
3437                              struct atomisp_de_config *config)
3438{
3439        struct ia_css_de_config de_config;
3440        struct ia_css_isp_config isp_config;
3441        struct atomisp_device *isp = asd->isp;
3442
3443        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3444                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3445                        __func__);
3446                return -EINVAL;
3447        }
3448        memset(&de_config, 0, sizeof(struct ia_css_de_config));
3449        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3450        isp_config.de_config = &de_config;
3451        ia_css_stream_get_isp_config(
3452            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3453            &isp_config);
3454        memcpy(config, &de_config, sizeof(*config));
3455
3456        return 0;
3457}
3458
3459int atomisp_css_get_nr_config(struct atomisp_sub_device *asd,
3460                              struct atomisp_nr_config *config)
3461{
3462        struct ia_css_nr_config nr_config;
3463        struct ia_css_isp_config isp_config;
3464        struct atomisp_device *isp = asd->isp;
3465
3466        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3467                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3468                        __func__);
3469                return -EINVAL;
3470        }
3471        memset(&nr_config, 0, sizeof(struct ia_css_nr_config));
3472        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3473
3474        isp_config.nr_config = &nr_config;
3475        ia_css_stream_get_isp_config(
3476            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3477            &isp_config);
3478        memcpy(config, &nr_config, sizeof(*config));
3479
3480        return 0;
3481}
3482
3483int atomisp_css_get_ee_config(struct atomisp_sub_device *asd,
3484                              struct atomisp_ee_config *config)
3485{
3486        struct ia_css_ee_config ee_config;
3487        struct ia_css_isp_config isp_config;
3488        struct atomisp_device *isp = asd->isp;
3489
3490        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3491                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3492                        __func__);
3493                return -EINVAL;
3494        }
3495        memset(&ee_config, 0, sizeof(struct ia_css_ee_config));
3496        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3497        isp_config.ee_config = &ee_config;
3498        ia_css_stream_get_isp_config(
3499            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3500            &isp_config);
3501        memcpy(config, &ee_config, sizeof(*config));
3502
3503        return 0;
3504}
3505
3506int atomisp_css_get_tnr_config(struct atomisp_sub_device *asd,
3507                               struct atomisp_tnr_config *config)
3508{
3509        struct ia_css_tnr_config tnr_config;
3510        struct ia_css_isp_config isp_config;
3511        struct atomisp_device *isp = asd->isp;
3512
3513        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3514                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3515                        __func__);
3516                return -EINVAL;
3517        }
3518        memset(&tnr_config, 0, sizeof(struct ia_css_tnr_config));
3519        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3520        isp_config.tnr_config = &tnr_config;
3521        ia_css_stream_get_isp_config(
3522            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3523            &isp_config);
3524        memcpy(config, &tnr_config, sizeof(*config));
3525
3526        return 0;
3527}
3528
3529int atomisp_css_get_ctc_table(struct atomisp_sub_device *asd,
3530                              struct atomisp_ctc_table *config)
3531{
3532        struct ia_css_ctc_table *tab;
3533        struct ia_css_isp_config isp_config;
3534        struct atomisp_device *isp = asd->isp;
3535
3536        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3537                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3538                        __func__);
3539                return -EINVAL;
3540        }
3541
3542        tab = vzalloc(sizeof(struct ia_css_ctc_table));
3543        if (!tab)
3544                return -ENOMEM;
3545
3546        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3547        isp_config.ctc_table = tab;
3548        ia_css_stream_get_isp_config(
3549            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3550            &isp_config);
3551        memcpy(config, tab, sizeof(*tab));
3552        vfree(tab);
3553
3554        return 0;
3555}
3556
3557int atomisp_css_get_gamma_table(struct atomisp_sub_device *asd,
3558                                struct atomisp_gamma_table *config)
3559{
3560        struct ia_css_gamma_table *tab;
3561        struct ia_css_isp_config isp_config;
3562        struct atomisp_device *isp = asd->isp;
3563
3564        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3565                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3566                        __func__);
3567                return -EINVAL;
3568        }
3569
3570        tab = vzalloc(sizeof(struct ia_css_gamma_table));
3571        if (!tab)
3572                return -ENOMEM;
3573
3574        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3575        isp_config.gamma_table = tab;
3576        ia_css_stream_get_isp_config(
3577            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3578            &isp_config);
3579        memcpy(config, tab, sizeof(*tab));
3580        vfree(tab);
3581
3582        return 0;
3583}
3584
3585int atomisp_css_get_gc_config(struct atomisp_sub_device *asd,
3586                              struct atomisp_gc_config *config)
3587{
3588        struct ia_css_gc_config gc_config;
3589        struct ia_css_isp_config isp_config;
3590        struct atomisp_device *isp = asd->isp;
3591
3592        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3593                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3594                        __func__);
3595                return -EINVAL;
3596        }
3597        memset(&gc_config, 0, sizeof(struct ia_css_gc_config));
3598        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3599        isp_config.gc_config = &gc_config;
3600        ia_css_stream_get_isp_config(
3601            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3602            &isp_config);
3603        /* Get gamma correction params from current setup */
3604        memcpy(config, &gc_config, sizeof(*config));
3605
3606        return 0;
3607}
3608
3609int atomisp_css_get_3a_config(struct atomisp_sub_device *asd,
3610                              struct atomisp_3a_config *config)
3611{
3612        struct ia_css_3a_config s3a_config;
3613        struct ia_css_isp_config isp_config;
3614        struct atomisp_device *isp = asd->isp;
3615
3616        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3617                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3618                        __func__);
3619                return -EINVAL;
3620        }
3621        memset(&s3a_config, 0, sizeof(struct ia_css_3a_config));
3622        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3623        isp_config.s3a_config = &s3a_config;
3624        ia_css_stream_get_isp_config(
3625            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3626            &isp_config);
3627        /* Get white balance from current setup */
3628        memcpy(config, &s3a_config, sizeof(*config));
3629
3630        return 0;
3631}
3632
3633int atomisp_css_get_formats_config(struct atomisp_sub_device *asd,
3634                                   struct atomisp_formats_config *config)
3635{
3636        struct ia_css_formats_config formats_config;
3637        struct ia_css_isp_config isp_config;
3638        struct atomisp_device *isp = asd->isp;
3639
3640        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3641                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3642                        __func__);
3643                return -EINVAL;
3644        }
3645        memset(&formats_config, 0, sizeof(formats_config));
3646        memset(&isp_config, 0, sizeof(isp_config));
3647        isp_config.formats_config = &formats_config;
3648        ia_css_stream_get_isp_config(
3649            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3650            &isp_config);
3651        /* Get narrow gamma from current setup */
3652        memcpy(config, &formats_config, sizeof(*config));
3653
3654        return 0;
3655}
3656
3657int atomisp_css_get_zoom_factor(struct atomisp_sub_device *asd,
3658                                unsigned int *zoom)
3659{
3660        struct ia_css_dz_config dz_config;  /** Digital Zoom */
3661        struct ia_css_isp_config isp_config;
3662        struct atomisp_device *isp = asd->isp;
3663
3664        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3665                dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3666                        __func__);
3667                return -EINVAL;
3668        }
3669        memset(&dz_config, 0, sizeof(struct ia_css_dz_config));
3670        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3671        isp_config.dz_config = &dz_config;
3672        ia_css_stream_get_isp_config(
3673            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3674            &isp_config);
3675        *zoom = dz_config.dx;
3676
3677        return 0;
3678}
3679
3680/*
3681 * Function to set/get image stablization statistics
3682 */
3683int atomisp_css_get_dis_stat(struct atomisp_sub_device *asd,
3684                             struct atomisp_dis_statistics *stats)
3685{
3686        struct atomisp_device *isp = asd->isp;
3687        struct atomisp_dis_buf *dis_buf;
3688        unsigned long flags;
3689
3690        if (!asd->params.dvs_stat->hor_prod.odd_real ||
3691            !asd->params.dvs_stat->hor_prod.odd_imag ||
3692            !asd->params.dvs_stat->hor_prod.even_real ||
3693            !asd->params.dvs_stat->hor_prod.even_imag ||
3694            !asd->params.dvs_stat->ver_prod.odd_real ||
3695            !asd->params.dvs_stat->ver_prod.odd_imag ||
3696            !asd->params.dvs_stat->ver_prod.even_real ||
3697            !asd->params.dvs_stat->ver_prod.even_imag)
3698                return -EINVAL;
3699
3700        /* isp needs to be streaming to get DIS statistics */
3701        spin_lock_irqsave(&isp->lock, flags);
3702        if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) {
3703                spin_unlock_irqrestore(&isp->lock, flags);
3704                return -EINVAL;
3705        }
3706        spin_unlock_irqrestore(&isp->lock, flags);
3707
3708        if (atomisp_compare_dvs_grid(asd, &stats->dvs2_stat.grid_info) != 0)
3709                /* If the grid info in the argument differs from the current
3710                   grid info, we tell the caller to reset the grid size and
3711                   try again. */
3712                return -EAGAIN;
3713
3714        spin_lock_irqsave(&asd->dis_stats_lock, flags);
3715        if (!asd->params.dis_proj_data_valid || list_empty(&asd->dis_stats)) {
3716                spin_unlock_irqrestore(&asd->dis_stats_lock, flags);
3717                dev_err(isp->dev, "dis statistics is not valid.\n");
3718                return -EAGAIN;
3719        }
3720
3721        dis_buf = list_entry(asd->dis_stats.next,
3722                             struct atomisp_dis_buf, list);
3723        list_del_init(&dis_buf->list);
3724        spin_unlock_irqrestore(&asd->dis_stats_lock, flags);
3725
3726        if (dis_buf->dvs_map)
3727                ia_css_translate_dvs2_statistics(
3728                    asd->params.dvs_stat, dis_buf->dvs_map);
3729        else
3730                ia_css_get_dvs2_statistics(asd->params.dvs_stat,
3731                                           dis_buf->dis_data);
3732        stats->exp_id = dis_buf->dis_data->exp_id;
3733
3734        spin_lock_irqsave(&asd->dis_stats_lock, flags);
3735        list_add_tail(&dis_buf->list, &asd->dis_stats);
3736        spin_unlock_irqrestore(&asd->dis_stats_lock, flags);
3737
3738        if (copy_to_user(stats->dvs2_stat.ver_prod.odd_real,
3739                         asd->params.dvs_stat->ver_prod.odd_real,
3740                         asd->params.dvs_ver_proj_bytes))
3741                return -EFAULT;
3742        if (copy_to_user(stats->dvs2_stat.ver_prod.odd_imag,
3743                         asd->params.dvs_stat->ver_prod.odd_imag,
3744                         asd->params.dvs_ver_proj_bytes))
3745                return -EFAULT;
3746        if (copy_to_user(stats->dvs2_stat.ver_prod.even_real,
3747                         asd->params.dvs_stat->ver_prod.even_real,
3748                         asd->params.dvs_ver_proj_bytes))
3749                return -EFAULT;
3750        if (copy_to_user(stats->dvs2_stat.ver_prod.even_imag,
3751                         asd->params.dvs_stat->ver_prod.even_imag,
3752                         asd->params.dvs_ver_proj_bytes))
3753                return -EFAULT;
3754        if (copy_to_user(stats->dvs2_stat.hor_prod.odd_real,
3755                         asd->params.dvs_stat->hor_prod.odd_real,
3756                         asd->params.dvs_hor_proj_bytes))
3757                return -EFAULT;
3758        if (copy_to_user(stats->dvs2_stat.hor_prod.odd_imag,
3759                         asd->params.dvs_stat->hor_prod.odd_imag,
3760                         asd->params.dvs_hor_proj_bytes))
3761                return -EFAULT;
3762        if (copy_to_user(stats->dvs2_stat.hor_prod.even_real,
3763                         asd->params.dvs_stat->hor_prod.even_real,
3764                         asd->params.dvs_hor_proj_bytes))
3765                return -EFAULT;
3766        if (copy_to_user(stats->dvs2_stat.hor_prod.even_imag,
3767                         asd->params.dvs_stat->hor_prod.even_imag,
3768                         asd->params.dvs_hor_proj_bytes))
3769                return -EFAULT;
3770
3771        return 0;
3772}
3773
3774struct ia_css_shading_table *atomisp_css_shading_table_alloc(
3775    unsigned int width, unsigned int height)
3776{
3777        return ia_css_shading_table_alloc(width, height);
3778}
3779
3780void atomisp_css_set_shading_table(struct atomisp_sub_device *asd,
3781                                   struct ia_css_shading_table *table)
3782{
3783        asd->params.config.shading_table = table;
3784}
3785
3786void atomisp_css_shading_table_free(struct ia_css_shading_table *table)
3787{
3788        ia_css_shading_table_free(table);
3789}
3790
3791struct ia_css_morph_table *atomisp_css_morph_table_allocate(
3792    unsigned int width, unsigned int height)
3793{
3794        return ia_css_morph_table_allocate(width, height);
3795}
3796
3797void atomisp_css_set_morph_table(struct atomisp_sub_device *asd,
3798                                 struct ia_css_morph_table *table)
3799{
3800        asd->params.config.morph_table = table;
3801}
3802
3803void atomisp_css_get_morph_table(struct atomisp_sub_device *asd,
3804                                 struct ia_css_morph_table *table)
3805{
3806        struct ia_css_isp_config isp_config;
3807        struct atomisp_device *isp = asd->isp;
3808
3809        if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3810                dev_err(isp->dev,
3811                        "%s called after streamoff, skipping.\n", __func__);
3812                return;
3813        }
3814        memset(table, 0, sizeof(struct ia_css_morph_table));
3815        memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3816        isp_config.morph_table = table;
3817        ia_css_stream_get_isp_config(
3818            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3819            &isp_config);
3820}
3821
3822void atomisp_css_morph_table_free(struct ia_css_morph_table *table)
3823{
3824        ia_css_morph_table_free(table);
3825}
3826
3827void atomisp_css_set_cont_prev_start_time(struct atomisp_device *isp,
3828        unsigned int overlap)
3829{
3830        /* CSS 2.0 doesn't support this API. */
3831        dev_dbg(isp->dev, "set cont prev start time is not supported.\n");
3832        return;
3833}
3834
3835void atomisp_css_acc_done(struct atomisp_sub_device *asd)
3836{
3837        complete(&asd->acc.acc_done);
3838}
3839
3840int atomisp_css_wait_acc_finish(struct atomisp_sub_device *asd)
3841{
3842        int ret = 0;
3843        struct atomisp_device *isp = asd->isp;
3844
3845        /* Unlock the isp mutex taken in IOCTL handler before sleeping! */
3846        rt_mutex_unlock(&isp->mutex);
3847        if (wait_for_completion_interruptible_timeout(&asd->acc.acc_done,
3848                ATOMISP_ISP_TIMEOUT_DURATION) == 0) {
3849                dev_err(isp->dev, "<%s: completion timeout\n", __func__);
3850                ia_css_debug_dump_sp_sw_debug_info();
3851                ia_css_debug_dump_debug_info(__func__);
3852                ret = -EIO;
3853        }
3854        rt_mutex_lock(&isp->mutex);
3855
3856        return ret;
3857}
3858
3859/* Set the ACC binary arguments */
3860int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw)
3861{
3862        unsigned int mem;
3863
3864        for (mem = 0; mem < ATOMISP_ACC_NR_MEMORY; mem++) {
3865                if (acc_fw->args[mem].length == 0)
3866                        continue;
3867
3868                ia_css_isp_param_set_css_mem_init(&acc_fw->fw->mem_initializers,
3869                                                  IA_CSS_PARAM_CLASS_PARAM, mem,
3870                                                  acc_fw->args[mem].css_ptr,
3871                                                  acc_fw->args[mem].length);
3872        }
3873
3874        return 0;
3875}
3876
3877/* Load acc binary extension */
3878int atomisp_css_load_acc_extension(struct atomisp_sub_device *asd,
3879                                   struct ia_css_fw_info *fw,
3880                                   enum ia_css_pipe_id pipe_id,
3881                                   unsigned int type)
3882{
3883        struct ia_css_fw_info **hd;
3884
3885        fw->next = NULL;
3886        hd = &(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
3887               .pipe_configs[pipe_id].acc_extension);
3888        while (*hd)
3889                hd = &(*hd)->next;
3890        *hd = fw;
3891
3892        asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
3893        .update_pipe[pipe_id] = true;
3894        return 0;
3895}
3896
3897/* Unload acc binary extension */
3898void atomisp_css_unload_acc_extension(struct atomisp_sub_device *asd,
3899                                      struct ia_css_fw_info *fw,
3900                                      enum ia_css_pipe_id pipe_id)
3901{
3902        struct ia_css_fw_info **hd;
3903
3904        hd = &(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
3905               .pipe_configs[pipe_id].acc_extension);
3906        while (*hd && *hd != fw)
3907                hd = &(*hd)->next;
3908        if (!*hd) {
3909                dev_err(asd->isp->dev, "did not find acc fw for removal\n");
3910                return;
3911        }
3912        *hd = fw->next;
3913        fw->next = NULL;
3914
3915        asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
3916        .update_pipe[pipe_id] = true;
3917}
3918
3919int atomisp_css_create_acc_pipe(struct atomisp_sub_device *asd)
3920{
3921        struct atomisp_device *isp = asd->isp;
3922        struct ia_css_pipe_config *pipe_config;
3923        struct atomisp_stream_env *stream_env =
3924                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
3925
3926        if (stream_env->acc_stream) {
3927                if (stream_env->acc_stream_state == CSS_STREAM_STARTED) {
3928                        if (ia_css_stream_stop(stream_env->acc_stream)
3929                            != 0) {
3930                                dev_err(isp->dev, "stop acc_stream failed.\n");
3931                                return -EBUSY;
3932                        }
3933                }
3934
3935                if (ia_css_stream_destroy(stream_env->acc_stream)
3936                    != 0) {
3937                        dev_err(isp->dev, "destroy acc_stream failed.\n");
3938                        return -EBUSY;
3939                }
3940                stream_env->acc_stream = NULL;
3941        }
3942
3943        pipe_config = &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC];
3944        ia_css_pipe_config_defaults(pipe_config);
3945        asd->acc.acc_stages = kzalloc(MAX_ACC_STAGES *
3946                                      sizeof(void *), GFP_KERNEL);
3947        if (!asd->acc.acc_stages)
3948                return -ENOMEM;
3949        pipe_config->acc_stages = asd->acc.acc_stages;
3950        pipe_config->mode = IA_CSS_PIPE_MODE_ACC;
3951        pipe_config->num_acc_stages = 0;
3952
3953        /*
3954         * We delay the ACC pipeline creation to atomisp_css_start_acc_pipe,
3955         * because pipe configuration will soon be changed by
3956         * atomisp_css_load_acc_binary()
3957         */
3958        return 0;
3959}
3960
3961int atomisp_css_start_acc_pipe(struct atomisp_sub_device *asd)
3962{
3963        struct atomisp_device *isp = asd->isp;
3964        struct atomisp_stream_env *stream_env =
3965                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
3966        struct ia_css_pipe_config *pipe_config =
3967                    &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC];
3968
3969        if (ia_css_pipe_create(pipe_config,
3970                               &stream_env->pipes[IA_CSS_PIPE_ID_ACC]) != 0) {
3971                dev_err(isp->dev, "%s: ia_css_pipe_create failed\n",
3972                        __func__);
3973                return -EBADE;
3974        }
3975
3976        memset(&stream_env->acc_stream_config, 0,
3977               sizeof(struct ia_css_stream_config));
3978        if (ia_css_stream_create(&stream_env->acc_stream_config, 1,
3979                                 &stream_env->pipes[IA_CSS_PIPE_ID_ACC],
3980                                 &stream_env->acc_stream) != 0) {
3981                dev_err(isp->dev, "%s: create acc_stream error.\n", __func__);
3982                return -EINVAL;
3983        }
3984        stream_env->acc_stream_state = CSS_STREAM_CREATED;
3985
3986        init_completion(&asd->acc.acc_done);
3987        asd->acc.pipeline = stream_env->pipes[IA_CSS_PIPE_ID_ACC];
3988
3989        atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_MAX, false);
3990
3991        if (ia_css_start_sp()) {
3992                dev_err(isp->dev, "start sp error.\n");
3993                return -EIO;
3994        }
3995
3996        if (ia_css_stream_start(stream_env->acc_stream)
3997            != 0) {
3998                dev_err(isp->dev, "acc_stream start error.\n");
3999                return -EIO;
4000        }
4001
4002        stream_env->acc_stream_state = CSS_STREAM_STARTED;
4003        return 0;
4004}
4005
4006int atomisp_css_stop_acc_pipe(struct atomisp_sub_device *asd)
4007{
4008        struct atomisp_stream_env *stream_env =
4009                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
4010        if (stream_env->acc_stream_state == CSS_STREAM_STARTED) {
4011                ia_css_stream_stop(stream_env->acc_stream);
4012                stream_env->acc_stream_state = CSS_STREAM_STOPPED;
4013        }
4014        return 0;
4015}
4016
4017void atomisp_css_destroy_acc_pipe(struct atomisp_sub_device *asd)
4018{
4019        struct atomisp_stream_env *stream_env =
4020                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
4021        if (stream_env->acc_stream) {
4022                if (ia_css_stream_destroy(stream_env->acc_stream)
4023                    != 0)
4024                        dev_warn(asd->isp->dev,
4025                                 "destroy acc_stream failed.\n");
4026                stream_env->acc_stream = NULL;
4027        }
4028
4029        if (stream_env->pipes[IA_CSS_PIPE_ID_ACC]) {
4030                if (ia_css_pipe_destroy(stream_env->pipes[IA_CSS_PIPE_ID_ACC])
4031                    != 0)
4032                        dev_warn(asd->isp->dev,
4033                                 "destroy ACC pipe failed.\n");
4034                stream_env->pipes[IA_CSS_PIPE_ID_ACC] = NULL;
4035                stream_env->update_pipe[IA_CSS_PIPE_ID_ACC] = false;
4036                ia_css_pipe_config_defaults(
4037                    &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]);
4038                ia_css_pipe_extra_config_defaults(
4039                    &stream_env->pipe_extra_configs[IA_CSS_PIPE_ID_ACC]);
4040        }
4041        asd->acc.pipeline = NULL;
4042
4043        /* css 2.0 API limitation: ia_css_stop_sp() could be only called after
4044         * destroy all pipes
4045         */
4046        ia_css_stop_sp();
4047
4048        kfree(asd->acc.acc_stages);
4049        asd->acc.acc_stages = NULL;
4050
4051        atomisp_freq_scaling(asd->isp, ATOMISP_DFS_MODE_LOW, false);
4052}
4053
4054int atomisp_css_load_acc_binary(struct atomisp_sub_device *asd,
4055                                struct ia_css_fw_info *fw,
4056                                unsigned int index)
4057{
4058        struct ia_css_pipe_config *pipe_config =
4059                    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
4060                    .pipe_configs[IA_CSS_PIPE_ID_ACC];
4061
4062        if (index >= MAX_ACC_STAGES) {
4063                dev_dbg(asd->isp->dev, "%s: index(%d) out of range\n",
4064                        __func__, index);
4065                return -ENOMEM;
4066        }
4067
4068        pipe_config->acc_stages[index] = fw;
4069        pipe_config->num_acc_stages = index + 1;
4070        pipe_config->acc_num_execs = 1;
4071
4072        return 0;
4073}
4074
4075static struct atomisp_sub_device *__get_atomisp_subdev(
4076    struct ia_css_pipe *css_pipe,
4077    struct atomisp_device *isp,
4078    enum atomisp_input_stream_id *stream_id)
4079{
4080        int i, j, k;
4081        struct atomisp_sub_device *asd;
4082        struct atomisp_stream_env *stream_env;
4083
4084        for (i = 0; i < isp->num_of_streams; i++) {
4085                asd = &isp->asd[i];
4086                if (asd->streaming == ATOMISP_DEVICE_STREAMING_DISABLED &&
4087                    !asd->acc.pipeline)
4088                        continue;
4089                for (j = 0; j < ATOMISP_INPUT_STREAM_NUM; j++) {
4090                        stream_env = &asd->stream_env[j];
4091                        for (k = 0; k < IA_CSS_PIPE_ID_NUM; k++) {
4092                                if (stream_env->pipes[k] &&
4093                                    stream_env->pipes[k] == css_pipe) {
4094                                        *stream_id = j;
4095                                        return asd;
4096                                }
4097                        }
4098                }
4099        }
4100
4101        return NULL;
4102}
4103
4104int atomisp_css_isr_thread(struct atomisp_device *isp,
4105                           bool *frame_done_found,
4106                           bool *css_pipe_done)
4107{
4108        enum atomisp_input_stream_id stream_id = 0;
4109        struct atomisp_css_event current_event;
4110        struct atomisp_sub_device *asd;
4111        bool reset_wdt_timer[MAX_STREAM_NUM] = {false};
4112        int i;
4113
4114        while (!atomisp_css_dequeue_event(&current_event)) {
4115                if (current_event.event.type ==
4116                    IA_CSS_EVENT_TYPE_FW_ASSERT) {
4117                        /*
4118                         * Received FW assertion signal,
4119                         * trigger WDT to recover
4120                         */
4121                        dev_err(isp->dev,
4122                                "%s: ISP reports FW_ASSERT event! fw_assert_module_id %d fw_assert_line_no %d\n",
4123                                __func__,
4124                                current_event.event.fw_assert_module_id,
4125                                current_event.event.fw_assert_line_no);
4126                        for (i = 0; i < isp->num_of_streams; i++)
4127                                atomisp_wdt_stop(&isp->asd[i], 0);
4128
4129                        if (!IS_ISP2401)
4130                                atomisp_wdt(&isp->asd[0].wdt);
4131                        else
4132                                queue_work(isp->wdt_work_queue, &isp->wdt_work);
4133
4134                        return -EINVAL;
4135                } else if (current_event.event.type == IA_CSS_EVENT_TYPE_FW_WARNING) {
4136                        dev_warn(isp->dev, "%s: ISP reports warning, code is %d, exp_id %d\n",
4137                                 __func__, current_event.event.fw_warning,
4138                                 current_event.event.exp_id);
4139                        continue;
4140                }
4141
4142                asd = __get_atomisp_subdev(current_event.event.pipe,
4143                                           isp, &stream_id);
4144                if (!asd) {
4145                        if (current_event.event.type == IA_CSS_EVENT_TYPE_TIMER)
4146                                dev_dbg(isp->dev,
4147                                        "event: Timer event.");
4148                        else
4149                                dev_warn(isp->dev, "%s:no subdev.event:%d",
4150                                         __func__,
4151                                         current_event.event.type);
4152                        continue;
4153                }
4154
4155                atomisp_css_temp_pipe_to_pipe_id(asd, &current_event);
4156                switch (current_event.event.type) {
4157                case IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE:
4158                        dev_dbg(isp->dev, "event: Output frame done");
4159                        frame_done_found[asd->index] = true;
4160                        atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME,
4161                                         current_event.pipe, true, stream_id);
4162
4163                        if (!IS_ISP2401)
4164                                reset_wdt_timer[asd->index] = true; /* ISP running */
4165
4166                        break;
4167                case IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE:
4168                        dev_dbg(isp->dev, "event: Second output frame done");
4169                        frame_done_found[asd->index] = true;
4170                        atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME,
4171                                         current_event.pipe, true, stream_id);
4172
4173                        if (!IS_ISP2401)
4174                                reset_wdt_timer[asd->index] = true; /* ISP running */
4175
4176                        break;
4177                case IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE:
4178                        dev_dbg(isp->dev, "event: 3A stats frame done");
4179                        atomisp_buf_done(asd, 0,
4180                                         IA_CSS_BUFFER_TYPE_3A_STATISTICS,
4181                                         current_event.pipe,
4182                                         false, stream_id);
4183                        break;
4184                case IA_CSS_EVENT_TYPE_METADATA_DONE:
4185                        dev_dbg(isp->dev, "event: metadata frame done");
4186                        atomisp_buf_done(asd, 0,
4187                                         IA_CSS_BUFFER_TYPE_METADATA,
4188                                         current_event.pipe,
4189                                         false, stream_id);
4190                        break;
4191                case IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE:
4192                        dev_dbg(isp->dev, "event: VF output frame done");
4193                        atomisp_buf_done(asd, 0,
4194                                         IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME,
4195                                         current_event.pipe, true, stream_id);
4196
4197                        if (!IS_ISP2401)
4198                                reset_wdt_timer[asd->index] = true; /* ISP running */
4199
4200                        break;
4201                case IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE:
4202                        dev_dbg(isp->dev, "event: second VF output frame done");
4203                        atomisp_buf_done(asd, 0,
4204                                         IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME,
4205                                         current_event.pipe, true, stream_id);
4206                        if (!IS_ISP2401)
4207                                reset_wdt_timer[asd->index] = true; /* ISP running */
4208
4209                        break;
4210                case IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE:
4211                        dev_dbg(isp->dev, "event: dis stats frame done");
4212                        atomisp_buf_done(asd, 0,
4213                                         IA_CSS_BUFFER_TYPE_DIS_STATISTICS,
4214                                         current_event.pipe,
4215                                         false, stream_id);
4216                        break;
4217                case IA_CSS_EVENT_TYPE_PIPELINE_DONE:
4218                        dev_dbg(isp->dev, "event: pipeline done");
4219                        css_pipe_done[asd->index] = true;
4220                        break;
4221                case IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE:
4222                        dev_dbg(isp->dev, "event: acc stage done");
4223                        atomisp_acc_done(asd, current_event.event.fw_handle);
4224                        break;
4225                default:
4226                        dev_dbg(isp->dev, "unhandled css stored event: 0x%x\n",
4227                                current_event.event.type);
4228                        break;
4229                }
4230        }
4231
4232        if (IS_ISP2401)
4233                return 0;
4234
4235        /* ISP2400: If there are no buffers queued then delete wdt timer. */
4236        for (i = 0; i < isp->num_of_streams; i++) {
4237                asd = &isp->asd[i];
4238                if (!asd)
4239                        continue;
4240                if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
4241                        continue;
4242                if (!atomisp_buffers_queued(asd))
4243                        atomisp_wdt_stop(asd, false);
4244                else if (reset_wdt_timer[i])
4245                        /* SOF irq should not reset wdt timer. */
4246                        atomisp_wdt_refresh(asd,
4247                                            ATOMISP_WDT_KEEP_CURRENT_DELAY);
4248        }
4249
4250        return 0;
4251}
4252
4253bool atomisp_css_valid_sof(struct atomisp_device *isp)
4254{
4255        unsigned int i, j;
4256
4257        /* Loop for each css stream */
4258        for (i = 0; i < isp->num_of_streams; i++) {
4259                struct atomisp_sub_device *asd = &isp->asd[i];
4260                /* Loop for each css vc stream */
4261                for (j = 0; j < ATOMISP_INPUT_STREAM_NUM; j++) {
4262                        if (!asd->stream_env[j].stream)
4263                                continue;
4264
4265                        dev_dbg(isp->dev,
4266                                "stream #%d: mode: %d\n", j,
4267                                asd->stream_env[j].stream_config.mode);
4268                        if (asd->stream_env[j].stream_config.mode ==
4269                            IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
4270                                return false;
4271                }
4272        }
4273
4274        return true;
4275}
4276
4277int atomisp_css_debug_dump_isp_binary(void)
4278{
4279        ia_css_debug_dump_isp_binary();
4280        return 0;
4281}
4282
4283int atomisp_css_dump_sp_raw_copy_linecount(bool reduced)
4284{
4285        sh_css_dump_sp_raw_copy_linecount(reduced);
4286        return 0;
4287}
4288
4289static const char * const fw_type_name[] = {
4290        [ia_css_sp_firmware]            = "SP",
4291        [ia_css_isp_firmware]           = "ISP",
4292        [ia_css_bootloader_firmware]    = "BootLoader",
4293        [ia_css_acc_firmware]           = "accel",
4294};
4295
4296static const char * const fw_acc_type_name[] = {
4297        [IA_CSS_ACC_NONE] =             "Normal",
4298        [IA_CSS_ACC_OUTPUT] =           "Accel stage on output",
4299        [IA_CSS_ACC_VIEWFINDER] =       "Accel stage on viewfinder",
4300        [IA_CSS_ACC_STANDALONE] =       "Stand-alone acceleration",
4301};
4302
4303int atomisp_css_dump_blob_infor(struct atomisp_device *isp)
4304{
4305        struct ia_css_blob_descr *bd = sh_css_blob_info;
4306        unsigned int i, nm = sh_css_num_binaries;
4307
4308        if (nm == 0)
4309                return -EPERM;
4310        if (!bd)
4311                return -EPERM;
4312
4313        /*
4314         * The sh_css_load_firmware function discard the initial
4315         * "SPS" binaries
4316         */
4317        for (i = 0; i < sh_css_num_binaries - NUM_OF_SPS; i++) {
4318                switch (bd[i].header.type) {
4319                case ia_css_isp_firmware:
4320                        dev_dbg(isp->dev, "Num%2d type %s (%s), binary id is %2d, name is %s\n",
4321                                i + NUM_OF_SPS,
4322                                fw_type_name[bd[i].header.type],
4323                                fw_acc_type_name[bd[i].header.info.isp.type],
4324                                bd[i].header.info.isp.sp.id,
4325                                bd[i].name);
4326                        break;
4327                default:
4328                        dev_dbg(isp->dev, "Num%2d type %s, name is %s\n",
4329                                i + NUM_OF_SPS, fw_type_name[bd[i].header.type],
4330                                bd[i].name);
4331                }
4332        }
4333
4334        return 0;
4335}
4336
4337void atomisp_css_set_isp_config_id(struct atomisp_sub_device *asd,
4338                                   uint32_t isp_config_id)
4339{
4340        asd->params.config.isp_config_id = isp_config_id;
4341}
4342
4343void atomisp_css_set_isp_config_applied_frame(struct atomisp_sub_device *asd,
4344        struct ia_css_frame *output_frame)
4345{
4346        asd->params.config.output_frame = output_frame;
4347}
4348
4349int atomisp_get_css_dbgfunc(void)
4350{
4351        return dbg_func;
4352}
4353
4354int atomisp_set_css_dbgfunc(struct atomisp_device *isp, int opt)
4355{
4356        int ret;
4357
4358        ret = __set_css_print_env(isp, opt);
4359        if (ret == 0)
4360                dbg_func = opt;
4361
4362        return ret;
4363}
4364
4365void atomisp_en_dz_capt_pipe(struct atomisp_sub_device *asd, bool enable)
4366{
4367        ia_css_en_dz_capt_pipe(
4368            asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
4369            enable);
4370}
4371
4372struct ia_css_dvs_grid_info *atomisp_css_get_dvs_grid_info(
4373    struct ia_css_grid_info *grid_info)
4374{
4375        if (!grid_info)
4376                return NULL;
4377
4378#ifdef IA_CSS_DVS_STAT_GRID_INFO_SUPPORTED
4379        return &grid_info->dvs_grid.dvs_grid_info;
4380#else
4381        return &grid_info->dvs_grid;
4382#endif
4383}
4384