linux/drivers/staging/media/atomisp/pci/sh_css.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Support for Intel Camera Imaging ISP subsystem.
   4 * Copyright (c) 2015, Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 */
  15
  16/*! \file */
  17#include <linux/mm.h>
  18#include <linux/slab.h>
  19#include <linux/vmalloc.h>
  20
  21#include "hmm.h"
  22
  23#include "ia_css.h"
  24#include "sh_css_hrt.h"         /* only for file 2 MIPI */
  25#include "ia_css_buffer.h"
  26#include "ia_css_binary.h"
  27#include "sh_css_internal.h"
  28#include "sh_css_mipi.h"
  29#include "sh_css_sp.h"          /* sh_css_sp_group */
  30#include "ia_css_isys.h"
  31#include "ia_css_frame.h"
  32#include "sh_css_defs.h"
  33#include "sh_css_firmware.h"
  34#include "sh_css_params.h"
  35#include "sh_css_params_internal.h"
  36#include "sh_css_param_shading.h"
  37#include "ia_css_refcount.h"
  38#include "ia_css_rmgr.h"
  39#include "ia_css_debug.h"
  40#include "ia_css_debug_pipe.h"
  41#include "ia_css_device_access.h"
  42#include "device_access.h"
  43#include "sh_css_legacy.h"
  44#include "ia_css_pipeline.h"
  45#include "ia_css_stream.h"
  46#include "sh_css_stream_format.h"
  47#include "ia_css_pipe.h"
  48#include "ia_css_util.h"
  49#include "ia_css_pipe_util.h"
  50#include "ia_css_pipe_binarydesc.h"
  51#include "ia_css_pipe_stagedesc.h"
  52
  53#include "tag.h"
  54#include "assert_support.h"
  55#include "math_support.h"
  56#include "sw_event_global.h"                    /* Event IDs.*/
  57#if !defined(ISP2401)
  58#include "ia_css_ifmtr.h"
  59#endif
  60#include "input_system.h"
  61#include "mmu_device.h"         /* mmu_set_page_table_base_index(), ... */
  62#include "ia_css_mmu_private.h" /* sh_css_mmu_set_page_table_base_index() */
  63#include "gdc_device.h"         /* HRT_GDC_N */
  64#include "dma.h"                /* dma_set_max_burst_size() */
  65#include "irq.h"                        /* virq */
  66#include "sp.h"                         /* cnd_sp_irq_enable() */
  67#include "isp.h"                        /* cnd_isp_irq_enable, ISP_VEC_NELEMS */
  68#include "gp_device.h"          /* gp_device_reg_store() */
  69#define __INLINE_GPIO__
  70#include "gpio.h"
  71#include "timed_ctrl.h"
  72#include "ia_css_inputfifo.h"
  73#define WITH_PC_MONITORING  0
  74
  75#define SH_CSS_VIDEO_BUFFER_ALIGNMENT 0
  76
  77#if WITH_PC_MONITORING
  78#define MULTIPLE_SAMPLES 1
  79#define NOF_SAMPLES      60
  80#include "linux/kthread.h"
  81#include "linux/sched.h"
  82#include "linux/delay.h"
  83#include "sh_css_metrics.h"
  84static int thread_alive;
  85#endif /* WITH_PC_MONITORING */
  86
  87#include "ia_css_spctrl.h"
  88#include "ia_css_version_data.h"
  89#include "sh_css_struct.h"
  90#include "ia_css_bufq.h"
  91#include "ia_css_timer.h" /* clock_value_t */
  92
  93#include "isp/modes/interface/input_buf.isp.h"
  94
  95/* Name of the sp program: should not be built-in */
  96#define SP_PROG_NAME "sp"
  97/* Size of Refcount List */
  98#define REFCOUNT_SIZE 1000
  99
 100/* for JPEG, we don't know the length of the image upfront,
 101 * but since we support sensor upto 16MP, we take this as
 102 * upper limit.
 103 */
 104#define JPEG_BYTES (16 * 1024 * 1024)
 105
 106#define STATS_ENABLED(stage) (stage && stage->binary && stage->binary->info && \
 107        (stage->binary->info->sp.enable.s3a || stage->binary->info->sp.enable.dis))
 108
 109struct sh_css my_css;
 110
 111int  __printf(1, 0) (*sh_css_printf)(const char *fmt, va_list args) = NULL;
 112
 113/* modes of work: stream_create and stream_destroy will update the save/restore data
 114   only when in working mode, not suspend/resume
 115*/
 116enum ia_sh_css_modes {
 117        sh_css_mode_none = 0,
 118        sh_css_mode_working,
 119        sh_css_mode_suspend,
 120        sh_css_mode_resume
 121};
 122
 123/* a stream seed, to save and restore the stream data.
 124   the stream seed contains all the data required to "grow" the seed again after it was closed.
 125*/
 126struct sh_css_stream_seed {
 127        struct ia_css_stream
 128                **orig_stream;                /* pointer to restore the original handle */
 129        struct ia_css_stream            *stream;                      /* handle, used as ID too.*/
 130        struct ia_css_stream_config     stream_config;                          /* stream config struct */
 131        int                             num_pipes;
 132        struct ia_css_pipe              *pipes[IA_CSS_PIPE_ID_NUM];                     /* pipe handles */
 133        struct ia_css_pipe
 134                **orig_pipes[IA_CSS_PIPE_ID_NUM];       /* pointer to restore original handle */
 135        struct ia_css_pipe_config
 136                pipe_config[IA_CSS_PIPE_ID_NUM];        /* pipe config structs */
 137};
 138
 139#define MAX_ACTIVE_STREAMS      5
 140/* A global struct for save/restore to hold all the data that should sustain power-down:
 141   MMU base, IRQ type, env for routines, binary loaded FW and the stream seeds.
 142*/
 143struct sh_css_save {
 144        enum ia_sh_css_modes            mode;
 145        u32                    mmu_base;                                /* the last mmu_base */
 146        enum ia_css_irq_type           irq_type;
 147        struct sh_css_stream_seed      stream_seeds[MAX_ACTIVE_STREAMS];
 148        struct ia_css_fw               *loaded_fw;                              /* fw struct previously loaded */
 149        struct ia_css_env              driver_env;                              /* driver-supplied env copy */
 150};
 151
 152static bool my_css_save_initialized;    /* if my_css_save was initialized */
 153static struct sh_css_save my_css_save;
 154
 155/* pqiao NOTICE: this is for css internal buffer recycling when stopping pipeline,
 156   this array is temporary and will be replaced by resource manager*/
 157/* Taking the biggest Size for number of Elements */
 158#define MAX_HMM_BUFFER_NUM      \
 159        (SH_CSS_MAX_NUM_QUEUES * (IA_CSS_NUM_ELEMS_SP2HOST_BUFFER_QUEUE + 2))
 160
 161struct sh_css_hmm_buffer_record {
 162        bool in_use;
 163        enum ia_css_buffer_type type;
 164        struct ia_css_rmgr_vbuf_handle *h_vbuf;
 165        hrt_address kernel_ptr;
 166};
 167
 168static struct sh_css_hmm_buffer_record hmm_buffer_record[MAX_HMM_BUFFER_NUM];
 169
 170#define GPIO_FLASH_PIN_MASK BIT(HIVE_GPIO_STROBE_TRIGGER_PIN)
 171
 172static bool fw_explicitly_loaded;
 173
 174/*
 175 * Local prototypes
 176 */
 177
 178static int
 179allocate_delay_frames(struct ia_css_pipe *pipe);
 180
 181static int
 182sh_css_pipe_start(struct ia_css_stream *stream);
 183
 184/* ISP 2401 */
 185/*
 186 * @brief Stop all "ia_css_pipe" instances in the target
 187 * "ia_css_stream" instance.
 188 *
 189 * @param[in] stream    Point to the target "ia_css_stream" instance.
 190 *
 191 * @return
 192 * - 0, if the "stop" requests have been successfully sent out.
 193 * - CSS error code, otherwise.
 194 *
 195 *
 196 * NOTE
 197 * This API sends the "stop" requests to the "ia_css_pipe"
 198 * instances in the same "ia_css_stream" instance. It will
 199 * return without waiting for all "ia_css_pipe" instatnces
 200 * being stopped.
 201 */
 202static int
 203sh_css_pipes_stop(struct ia_css_stream *stream);
 204
 205/*
 206 * @brief Check if all "ia_css_pipe" instances in the target
 207 * "ia_css_stream" instance have stopped.
 208 *
 209 * @param[in] stream    Point to the target "ia_css_stream" instance.
 210 *
 211 * @return
 212 * - true, if all "ia_css_pipe" instances in the target "ia_css_stream"
 213 *   instance have ben stopped.
 214 * - false, otherwise.
 215 */
 216/* ISP 2401 */
 217static bool
 218sh_css_pipes_have_stopped(struct ia_css_stream *stream);
 219
 220/* ISP 2401 */
 221static int
 222ia_css_pipe_check_format(struct ia_css_pipe *pipe,
 223                         enum ia_css_frame_format format);
 224
 225/* ISP 2401 */
 226static int
 227check_pipe_resolutions(const struct ia_css_pipe *pipe);
 228
 229static int
 230ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
 231                           struct ia_css_fw_info *firmware);
 232
 233static void
 234ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
 235                             struct ia_css_fw_info *firmware);
 236static void
 237ia_css_reset_defaults(struct sh_css *css);
 238
 239static void
 240sh_css_init_host_sp_control_vars(void);
 241
 242static int
 243set_num_primary_stages(unsigned int *num, enum ia_css_pipe_version version);
 244
 245static bool
 246need_capture_pp(const struct ia_css_pipe *pipe);
 247
 248static bool
 249need_yuv_scaler_stage(const struct ia_css_pipe *pipe);
 250
 251static int ia_css_pipe_create_cas_scaler_desc_single_output(
 252    struct ia_css_frame_info *cas_scaler_in_info,
 253    struct ia_css_frame_info *cas_scaler_out_info,
 254    struct ia_css_frame_info *cas_scaler_vf_info,
 255    struct ia_css_cas_binary_descr *descr);
 256
 257static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
 258        *descr);
 259
 260static bool
 261need_downscaling(const struct ia_css_resolution in_res,
 262                 const struct ia_css_resolution out_res);
 263
 264static bool need_capt_ldc(const struct ia_css_pipe *pipe);
 265
 266static int
 267sh_css_pipe_load_binaries(struct ia_css_pipe *pipe);
 268
 269static
 270int sh_css_pipe_get_viewfinder_frame_info(
 271    struct ia_css_pipe *pipe,
 272    struct ia_css_frame_info *info,
 273    unsigned int idx);
 274
 275static int
 276sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
 277                                  struct ia_css_frame_info *info,
 278                                  unsigned int idx);
 279
 280static int
 281capture_start(struct ia_css_pipe *pipe);
 282
 283static int
 284video_start(struct ia_css_pipe *pipe);
 285
 286static int
 287preview_start(struct ia_css_pipe *pipe);
 288
 289static int
 290yuvpp_start(struct ia_css_pipe *pipe);
 291
 292static bool copy_on_sp(struct ia_css_pipe *pipe);
 293
 294static int
 295init_vf_frameinfo_defaults(struct ia_css_pipe *pipe,
 296                           struct ia_css_frame *vf_frame, unsigned int idx);
 297
 298static int
 299init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
 300                                  struct ia_css_frame *frame, enum ia_css_frame_format format);
 301
 302static int
 303init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
 304                            struct ia_css_frame *out_frame, unsigned int idx);
 305
 306static int
 307sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
 308                              const void *acc_fw);
 309
 310static int
 311alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time);
 312
 313static void
 314pipe_global_init(void);
 315
 316static int
 317pipe_generate_pipe_num(const struct ia_css_pipe *pipe,
 318                       unsigned int *pipe_number);
 319
 320static void
 321pipe_release_pipe_num(unsigned int pipe_num);
 322
 323static int
 324create_host_pipeline_structure(struct ia_css_stream *stream);
 325
 326static int
 327create_host_pipeline(struct ia_css_stream *stream);
 328
 329static int
 330create_host_preview_pipeline(struct ia_css_pipe *pipe);
 331
 332static int
 333create_host_video_pipeline(struct ia_css_pipe *pipe);
 334
 335static int
 336create_host_copy_pipeline(struct ia_css_pipe *pipe,
 337                          unsigned int max_input_width,
 338                          struct ia_css_frame *out_frame);
 339
 340static int
 341create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe);
 342
 343static int
 344create_host_capture_pipeline(struct ia_css_pipe *pipe);
 345
 346static int
 347create_host_yuvpp_pipeline(struct ia_css_pipe *pipe);
 348
 349static int
 350create_host_acc_pipeline(struct ia_css_pipe *pipe);
 351
 352static unsigned int
 353sh_css_get_sw_interrupt_value(unsigned int irq);
 354
 355static struct ia_css_binary *ia_css_pipe_get_shading_correction_binary(
 356    const struct ia_css_pipe *pipe);
 357
 358static struct ia_css_binary *
 359ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe);
 360
 361static struct ia_css_binary *
 362ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe);
 363
 364static void
 365sh_css_hmm_buffer_record_init(void);
 366
 367static void
 368sh_css_hmm_buffer_record_uninit(void);
 369
 370static void
 371sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record);
 372
 373static struct sh_css_hmm_buffer_record
 374*sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf,
 375                                  enum ia_css_buffer_type type,
 376                                  hrt_address kernel_ptr);
 377
 378static struct sh_css_hmm_buffer_record
 379*sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr,
 380                                   enum ia_css_buffer_type type);
 381
 382void
 383ia_css_get_acc_configs(
 384    struct ia_css_pipe *pipe,
 385    struct ia_css_isp_config *config);
 386
 387#if CONFIG_ON_FRAME_ENQUEUE()
 388static int set_config_on_frame_enqueue(struct ia_css_frame_info
 389        *info, struct frame_data_wrapper *frame);
 390#endif
 391
 392#ifdef ISP2401
 393static unsigned int get_crop_lines_for_bayer_order(const struct
 394        ia_css_stream_config *config);
 395static unsigned int get_crop_columns_for_bayer_order(const struct
 396        ia_css_stream_config *config);
 397static void get_pipe_extra_pixel(struct ia_css_pipe *pipe,
 398                                 unsigned int *extra_row, unsigned int *extra_column);
 399static int
 400aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
 401                       struct ia_css_pipe *pipes[],
 402                       bool *do_crop_status);
 403
 404static bool
 405aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe);
 406
 407static int
 408aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
 409                  struct ia_css_resolution *effective_res);
 410#endif
 411
 412static void
 413sh_css_pipe_free_shading_table(struct ia_css_pipe *pipe)
 414{
 415        if (!pipe) {
 416                IA_CSS_ERROR("NULL input parameter");
 417                return;
 418        }
 419
 420        if (pipe->shading_table)
 421                ia_css_shading_table_free(pipe->shading_table);
 422        pipe->shading_table = NULL;
 423}
 424
 425static enum ia_css_frame_format yuv420_copy_formats[] = {
 426        IA_CSS_FRAME_FORMAT_NV12,
 427        IA_CSS_FRAME_FORMAT_NV21,
 428        IA_CSS_FRAME_FORMAT_YV12,
 429        IA_CSS_FRAME_FORMAT_YUV420,
 430        IA_CSS_FRAME_FORMAT_YUV420_16,
 431        IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8,
 432        IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8
 433};
 434
 435static enum ia_css_frame_format yuv422_copy_formats[] = {
 436        IA_CSS_FRAME_FORMAT_NV12,
 437        IA_CSS_FRAME_FORMAT_NV16,
 438        IA_CSS_FRAME_FORMAT_NV21,
 439        IA_CSS_FRAME_FORMAT_NV61,
 440        IA_CSS_FRAME_FORMAT_YV12,
 441        IA_CSS_FRAME_FORMAT_YV16,
 442        IA_CSS_FRAME_FORMAT_YUV420,
 443        IA_CSS_FRAME_FORMAT_YUV420_16,
 444        IA_CSS_FRAME_FORMAT_YUV422,
 445        IA_CSS_FRAME_FORMAT_YUV422_16,
 446        IA_CSS_FRAME_FORMAT_UYVY,
 447        IA_CSS_FRAME_FORMAT_YUYV
 448};
 449
 450/* Verify whether the selected output format is can be produced
 451 * by the copy binary given the stream format.
 452 * */
 453static int
 454verify_copy_out_frame_format(struct ia_css_pipe *pipe)
 455{
 456        enum ia_css_frame_format out_fmt = pipe->output_info[0].format;
 457        unsigned int i, found = 0;
 458
 459        assert(pipe);
 460        assert(pipe->stream);
 461
 462        switch (pipe->stream->config.input_config.format) {
 463        case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:
 464        case ATOMISP_INPUT_FORMAT_YUV420_8:
 465                for (i = 0; i < ARRAY_SIZE(yuv420_copy_formats) && !found; i++)
 466                        found = (out_fmt == yuv420_copy_formats[i]);
 467                break;
 468        case ATOMISP_INPUT_FORMAT_YUV420_10:
 469        case ATOMISP_INPUT_FORMAT_YUV420_16:
 470                found = (out_fmt == IA_CSS_FRAME_FORMAT_YUV420_16);
 471                break;
 472        case ATOMISP_INPUT_FORMAT_YUV422_8:
 473                for (i = 0; i < ARRAY_SIZE(yuv422_copy_formats) && !found; i++)
 474                        found = (out_fmt == yuv422_copy_formats[i]);
 475                break;
 476        case ATOMISP_INPUT_FORMAT_YUV422_10:
 477        case ATOMISP_INPUT_FORMAT_YUV422_16:
 478                found = (out_fmt == IA_CSS_FRAME_FORMAT_YUV422_16 ||
 479                         out_fmt == IA_CSS_FRAME_FORMAT_YUV420_16);
 480                break;
 481        case ATOMISP_INPUT_FORMAT_RGB_444:
 482        case ATOMISP_INPUT_FORMAT_RGB_555:
 483        case ATOMISP_INPUT_FORMAT_RGB_565:
 484                found = (out_fmt == IA_CSS_FRAME_FORMAT_RGBA888 ||
 485                         out_fmt == IA_CSS_FRAME_FORMAT_RGB565);
 486                break;
 487        case ATOMISP_INPUT_FORMAT_RGB_666:
 488        case ATOMISP_INPUT_FORMAT_RGB_888:
 489                found = (out_fmt == IA_CSS_FRAME_FORMAT_RGBA888 ||
 490                         out_fmt == IA_CSS_FRAME_FORMAT_YUV420);
 491                break;
 492        case ATOMISP_INPUT_FORMAT_RAW_6:
 493        case ATOMISP_INPUT_FORMAT_RAW_7:
 494        case ATOMISP_INPUT_FORMAT_RAW_8:
 495        case ATOMISP_INPUT_FORMAT_RAW_10:
 496        case ATOMISP_INPUT_FORMAT_RAW_12:
 497        case ATOMISP_INPUT_FORMAT_RAW_14:
 498        case ATOMISP_INPUT_FORMAT_RAW_16:
 499                found = (out_fmt == IA_CSS_FRAME_FORMAT_RAW) ||
 500                (out_fmt == IA_CSS_FRAME_FORMAT_RAW_PACKED);
 501                break;
 502        case ATOMISP_INPUT_FORMAT_BINARY_8:
 503                found = (out_fmt == IA_CSS_FRAME_FORMAT_BINARY_8);
 504                break;
 505        default:
 506                break;
 507        }
 508        if (!found)
 509                return -EINVAL;
 510        return 0;
 511}
 512
 513unsigned int
 514ia_css_stream_input_format_bits_per_pixel(struct ia_css_stream *stream)
 515{
 516        int bpp = 0;
 517
 518        if (stream)
 519                bpp = ia_css_util_input_format_bpp(stream->config.input_config.format,
 520                                                   stream->config.pixels_per_clock == 2);
 521
 522        return bpp;
 523}
 524
 525#define GP_ISEL_TPG_MODE 0x90058
 526
 527#if !defined(ISP2401)
 528static int
 529sh_css_config_input_network(struct ia_css_stream *stream)
 530{
 531        unsigned int fmt_type;
 532        struct ia_css_pipe *pipe = stream->last_pipe;
 533        struct ia_css_binary *binary = NULL;
 534        int err = 0;
 535
 536        assert(stream);
 537        assert(pipe);
 538
 539        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
 540                            "sh_css_config_input_network() enter:\n");
 541
 542        if (pipe->pipeline.stages)
 543                binary = pipe->pipeline.stages->binary;
 544
 545        err = ia_css_isys_convert_stream_format_to_mipi_format(
 546            stream->config.input_config.format,
 547            stream->csi_rx_config.comp,
 548            &fmt_type);
 549        if (err)
 550                return err;
 551        sh_css_sp_program_input_circuit(fmt_type,
 552                                        stream->config.channel_id,
 553                                        stream->config.mode);
 554
 555        if ((binary && (binary->online || stream->config.continuous)) ||
 556            pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
 557                err = ia_css_ifmtr_configure(&stream->config,
 558                                             binary);
 559                if (err)
 560                        return err;
 561        }
 562
 563        if (stream->config.mode == IA_CSS_INPUT_MODE_TPG ||
 564            stream->config.mode == IA_CSS_INPUT_MODE_PRBS) {
 565                unsigned int hblank_cycles = 100,
 566                vblank_lines = 6,
 567                width,
 568                height,
 569                vblank_cycles;
 570                width  = (stream->config.input_config.input_res.width) / (1 +
 571                        (stream->config.pixels_per_clock == 2));
 572                height = stream->config.input_config.input_res.height;
 573                vblank_cycles = vblank_lines * (width + hblank_cycles);
 574                sh_css_sp_configure_sync_gen(width, height, hblank_cycles,
 575                                             vblank_cycles);
 576                if (!IS_ISP2401) {
 577                        if (pipe->stream->config.mode == IA_CSS_INPUT_MODE_TPG) {
 578                                /* TODO: move define to proper file in tools */
 579                                ia_css_device_store_uint32(GP_ISEL_TPG_MODE, 0);
 580                        }
 581                }
 582        }
 583        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
 584                            "sh_css_config_input_network() leave:\n");
 585        return 0;
 586}
 587#elif defined(ISP2401)
 588static unsigned int csi2_protocol_calculate_max_subpixels_per_line(
 589    enum atomisp_input_format   format,
 590    unsigned int                        pixels_per_line)
 591{
 592        unsigned int rval;
 593
 594        switch (format) {
 595        case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:
 596                /*
 597                 * The frame format layout is shown below.
 598                 *
 599                 *              Line    0:      UYY0 UYY0 ... UYY0
 600                 *              Line    1:      VYY0 VYY0 ... VYY0
 601                 *              Line    2:      UYY0 UYY0 ... UYY0
 602                 *              Line    3:      VYY0 VYY0 ... VYY0
 603                 *              ...
 604                 *              Line (n-2):     UYY0 UYY0 ... UYY0
 605                 *              Line (n-1):     VYY0 VYY0 ... VYY0
 606                 *
 607                 *      In this frame format, the even-line is
 608                 *      as wide as the odd-line.
 609                 *      The 0 is introduced by the input system
 610                 *      (mipi backend).
 611                 */
 612                rval = pixels_per_line * 2;
 613                break;
 614        case ATOMISP_INPUT_FORMAT_YUV420_8:
 615        case ATOMISP_INPUT_FORMAT_YUV420_10:
 616        case ATOMISP_INPUT_FORMAT_YUV420_16:
 617                /*
 618                 * The frame format layout is shown below.
 619                 *
 620                 *              Line    0:      YYYY YYYY ... YYYY
 621                 *              Line    1:      UYVY UYVY ... UYVY UYVY
 622                 *              Line    2:      YYYY YYYY ... YYYY
 623                 *              Line    3:      UYVY UYVY ... UYVY UYVY
 624                 *              ...
 625                 *              Line (n-2):     YYYY YYYY ... YYYY
 626                 *              Line (n-1):     UYVY UYVY ... UYVY UYVY
 627                 *
 628                 * In this frame format, the odd-line is twice
 629                 * wider than the even-line.
 630                 */
 631                rval = pixels_per_line * 2;
 632                break;
 633        case ATOMISP_INPUT_FORMAT_YUV422_8:
 634        case ATOMISP_INPUT_FORMAT_YUV422_10:
 635        case ATOMISP_INPUT_FORMAT_YUV422_16:
 636                /*
 637                 * The frame format layout is shown below.
 638                 *
 639                 *              Line    0:      UYVY UYVY ... UYVY
 640                 *              Line    1:      UYVY UYVY ... UYVY
 641                 *              Line    2:      UYVY UYVY ... UYVY
 642                 *              Line    3:      UYVY UYVY ... UYVY
 643                 *              ...
 644                 *              Line (n-2):     UYVY UYVY ... UYVY
 645                 *              Line (n-1):     UYVY UYVY ... UYVY
 646                 *
 647                 * In this frame format, the even-line is
 648                 * as wide as the odd-line.
 649                 */
 650                rval = pixels_per_line * 2;
 651                break;
 652        case ATOMISP_INPUT_FORMAT_RGB_444:
 653        case ATOMISP_INPUT_FORMAT_RGB_555:
 654        case ATOMISP_INPUT_FORMAT_RGB_565:
 655        case ATOMISP_INPUT_FORMAT_RGB_666:
 656        case ATOMISP_INPUT_FORMAT_RGB_888:
 657                /*
 658                 * The frame format layout is shown below.
 659                 *
 660                 *              Line    0:      ABGR ABGR ... ABGR
 661                 *              Line    1:      ABGR ABGR ... ABGR
 662                 *              Line    2:      ABGR ABGR ... ABGR
 663                 *              Line    3:      ABGR ABGR ... ABGR
 664                 *              ...
 665                 *              Line (n-2):     ABGR ABGR ... ABGR
 666                 *              Line (n-1):     ABGR ABGR ... ABGR
 667                 *
 668                 * In this frame format, the even-line is
 669                 * as wide as the odd-line.
 670                 */
 671                rval = pixels_per_line * 4;
 672                break;
 673        case ATOMISP_INPUT_FORMAT_RAW_6:
 674        case ATOMISP_INPUT_FORMAT_RAW_7:
 675        case ATOMISP_INPUT_FORMAT_RAW_8:
 676        case ATOMISP_INPUT_FORMAT_RAW_10:
 677        case ATOMISP_INPUT_FORMAT_RAW_12:
 678        case ATOMISP_INPUT_FORMAT_RAW_14:
 679        case ATOMISP_INPUT_FORMAT_RAW_16:
 680        case ATOMISP_INPUT_FORMAT_BINARY_8:
 681        case ATOMISP_INPUT_FORMAT_USER_DEF1:
 682        case ATOMISP_INPUT_FORMAT_USER_DEF2:
 683        case ATOMISP_INPUT_FORMAT_USER_DEF3:
 684        case ATOMISP_INPUT_FORMAT_USER_DEF4:
 685        case ATOMISP_INPUT_FORMAT_USER_DEF5:
 686        case ATOMISP_INPUT_FORMAT_USER_DEF6:
 687        case ATOMISP_INPUT_FORMAT_USER_DEF7:
 688        case ATOMISP_INPUT_FORMAT_USER_DEF8:
 689                /*
 690                 * The frame format layout is shown below.
 691                 *
 692                 *              Line    0:      Pixel Pixel ... Pixel
 693                 *              Line    1:      Pixel Pixel ... Pixel
 694                 *              Line    2:      Pixel Pixel ... Pixel
 695                 *              Line    3:      Pixel Pixel ... Pixel
 696                 *              ...
 697                 *              Line (n-2):     Pixel Pixel ... Pixel
 698                 *              Line (n-1):     Pixel Pixel ... Pixel
 699                 *
 700                 * In this frame format, the even-line is
 701                 * as wide as the odd-line.
 702                 */
 703                rval = pixels_per_line;
 704                break;
 705        default:
 706                rval = 0;
 707                break;
 708        }
 709
 710        return rval;
 711}
 712
 713static bool sh_css_translate_stream_cfg_to_input_system_input_port_id(
 714    struct ia_css_stream_config *stream_cfg,
 715    ia_css_isys_descr_t *isys_stream_descr)
 716{
 717        bool rc;
 718
 719        rc = true;
 720        switch (stream_cfg->mode) {
 721        case IA_CSS_INPUT_MODE_TPG:
 722
 723                if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID0)
 724                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID;
 725                else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID1)
 726                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID;
 727                else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID2)
 728                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID;
 729
 730                break;
 731        case IA_CSS_INPUT_MODE_PRBS:
 732
 733                if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID0)
 734                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID;
 735                else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID1)
 736                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID;
 737                else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID2)
 738                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID;
 739
 740                break;
 741        case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
 742
 743                if (stream_cfg->source.port.port == MIPI_PORT0_ID)
 744                        isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT0_ID;
 745                else if (stream_cfg->source.port.port == MIPI_PORT1_ID)
 746                        isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT1_ID;
 747                else if (stream_cfg->source.port.port == MIPI_PORT2_ID)
 748                        isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT2_ID;
 749
 750                break;
 751        default:
 752                rc = false;
 753                break;
 754        }
 755
 756        return rc;
 757}
 758
 759static bool sh_css_translate_stream_cfg_to_input_system_input_port_type(
 760    struct ia_css_stream_config *stream_cfg,
 761    ia_css_isys_descr_t *isys_stream_descr)
 762{
 763        bool rc;
 764
 765        rc = true;
 766        switch (stream_cfg->mode) {
 767        case IA_CSS_INPUT_MODE_TPG:
 768
 769                isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_TPG;
 770
 771                break;
 772        case IA_CSS_INPUT_MODE_PRBS:
 773
 774                isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_PRBS;
 775
 776                break;
 777        case IA_CSS_INPUT_MODE_SENSOR:
 778        case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
 779
 780                isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_SENSOR;
 781                break;
 782
 783        default:
 784                rc = false;
 785                break;
 786        }
 787
 788        return rc;
 789}
 790
 791static bool sh_css_translate_stream_cfg_to_input_system_input_port_attr(
 792    struct ia_css_stream_config *stream_cfg,
 793    ia_css_isys_descr_t *isys_stream_descr,
 794    int isys_stream_idx)
 795{
 796        bool rc;
 797
 798        rc = true;
 799        switch (stream_cfg->mode) {
 800        case IA_CSS_INPUT_MODE_TPG:
 801                if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_RAMP)
 802                        isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_RAMP;
 803                else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_CHECKERBOARD)
 804                        isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_CHBO;
 805                else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_MONO)
 806                        isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_MONO;
 807                else
 808                        rc = false;
 809
 810                /*
 811                 * TODO
 812                 * - Make "color_cfg" as part of "ia_css_tpg_config".
 813                 */
 814                isys_stream_descr->tpg_port_attr.color_cfg.R1 = 51;
 815                isys_stream_descr->tpg_port_attr.color_cfg.G1 = 102;
 816                isys_stream_descr->tpg_port_attr.color_cfg.B1 = 255;
 817                isys_stream_descr->tpg_port_attr.color_cfg.R2 = 0;
 818                isys_stream_descr->tpg_port_attr.color_cfg.G2 = 100;
 819                isys_stream_descr->tpg_port_attr.color_cfg.B2 = 160;
 820
 821                isys_stream_descr->tpg_port_attr.mask_cfg.h_mask =
 822                    stream_cfg->source.tpg.x_mask;
 823                isys_stream_descr->tpg_port_attr.mask_cfg.v_mask =
 824                    stream_cfg->source.tpg.y_mask;
 825                isys_stream_descr->tpg_port_attr.mask_cfg.hv_mask =
 826                    stream_cfg->source.tpg.xy_mask;
 827
 828                isys_stream_descr->tpg_port_attr.delta_cfg.h_delta =
 829                    stream_cfg->source.tpg.x_delta;
 830                isys_stream_descr->tpg_port_attr.delta_cfg.v_delta =
 831                    stream_cfg->source.tpg.y_delta;
 832
 833                /*
 834                 * TODO
 835                 * - Make "sync_gen_cfg" as part of "ia_css_tpg_config".
 836                 */
 837                isys_stream_descr->tpg_port_attr.sync_gen_cfg.hblank_cycles = 100;
 838                isys_stream_descr->tpg_port_attr.sync_gen_cfg.vblank_cycles = 100;
 839                isys_stream_descr->tpg_port_attr.sync_gen_cfg.pixels_per_clock =
 840                    stream_cfg->pixels_per_clock;
 841                isys_stream_descr->tpg_port_attr.sync_gen_cfg.nr_of_frames = (uint32_t)~(0x0);
 842                isys_stream_descr->tpg_port_attr.sync_gen_cfg.pixels_per_line =
 843                    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.width;
 844                isys_stream_descr->tpg_port_attr.sync_gen_cfg.lines_per_frame =
 845                    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.height;
 846
 847                break;
 848        case IA_CSS_INPUT_MODE_PRBS:
 849
 850                isys_stream_descr->prbs_port_attr.seed0 = stream_cfg->source.prbs.seed;
 851                isys_stream_descr->prbs_port_attr.seed1 = stream_cfg->source.prbs.seed1;
 852
 853                /*
 854                 * TODO
 855                 * - Make "sync_gen_cfg" as part of "ia_css_prbs_config".
 856                 */
 857                isys_stream_descr->prbs_port_attr.sync_gen_cfg.hblank_cycles = 100;
 858                isys_stream_descr->prbs_port_attr.sync_gen_cfg.vblank_cycles = 100;
 859                isys_stream_descr->prbs_port_attr.sync_gen_cfg.pixels_per_clock =
 860                    stream_cfg->pixels_per_clock;
 861                isys_stream_descr->prbs_port_attr.sync_gen_cfg.nr_of_frames = (uint32_t)~(0x0);
 862                isys_stream_descr->prbs_port_attr.sync_gen_cfg.pixels_per_line =
 863                    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.width;
 864                isys_stream_descr->prbs_port_attr.sync_gen_cfg.lines_per_frame =
 865                    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.height;
 866
 867                break;
 868        case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: {
 869                int err;
 870                unsigned int fmt_type;
 871
 872                err = ia_css_isys_convert_stream_format_to_mipi_format(
 873                          stream_cfg->isys_config[isys_stream_idx].format,
 874                          MIPI_PREDICTOR_NONE,
 875                          &fmt_type);
 876                if (err)
 877                        rc = false;
 878
 879                isys_stream_descr->csi_port_attr.active_lanes =
 880                    stream_cfg->source.port.num_lanes;
 881                isys_stream_descr->csi_port_attr.fmt_type = fmt_type;
 882                isys_stream_descr->csi_port_attr.ch_id = stream_cfg->channel_id;
 883#ifdef ISP2401
 884                isys_stream_descr->online = stream_cfg->online;
 885#endif
 886                err |= ia_css_isys_convert_compressed_format(
 887                           &stream_cfg->source.port.compression,
 888                           isys_stream_descr);
 889                if (err)
 890                        rc = false;
 891
 892                /* metadata */
 893                isys_stream_descr->metadata.enable = false;
 894                if (stream_cfg->metadata_config.resolution.height > 0) {
 895                        err = ia_css_isys_convert_stream_format_to_mipi_format(
 896                                  stream_cfg->metadata_config.data_type,
 897                                  MIPI_PREDICTOR_NONE,
 898                                  &fmt_type);
 899                        if (err)
 900                                rc = false;
 901                        isys_stream_descr->metadata.fmt_type = fmt_type;
 902                        isys_stream_descr->metadata.bits_per_pixel =
 903                            ia_css_util_input_format_bpp(stream_cfg->metadata_config.data_type, true);
 904                        isys_stream_descr->metadata.pixels_per_line =
 905                            stream_cfg->metadata_config.resolution.width;
 906                        isys_stream_descr->metadata.lines_per_frame =
 907                            stream_cfg->metadata_config.resolution.height;
 908#ifdef ISP2401
 909                        /* For new input system, number of str2mmio requests must be even.
 910                         * So we round up number of metadata lines to be even. */
 911                        if (isys_stream_descr->metadata.lines_per_frame > 0)
 912                                isys_stream_descr->metadata.lines_per_frame +=
 913                                    (isys_stream_descr->metadata.lines_per_frame & 1);
 914#endif
 915                        isys_stream_descr->metadata.align_req_in_bytes =
 916                            ia_css_csi2_calculate_input_system_alignment(
 917                                stream_cfg->metadata_config.data_type);
 918                        isys_stream_descr->metadata.enable = true;
 919                }
 920
 921                break;
 922        }
 923        default:
 924                rc = false;
 925                break;
 926        }
 927
 928        return rc;
 929}
 930
 931static bool sh_css_translate_stream_cfg_to_input_system_input_port_resolution(
 932    struct ia_css_stream_config *stream_cfg,
 933    ia_css_isys_descr_t *isys_stream_descr,
 934    int isys_stream_idx)
 935{
 936        unsigned int bits_per_subpixel;
 937        unsigned int max_subpixels_per_line;
 938        unsigned int lines_per_frame;
 939        unsigned int align_req_in_bytes;
 940        enum atomisp_input_format fmt_type;
 941
 942        fmt_type = stream_cfg->isys_config[isys_stream_idx].format;
 943        if ((stream_cfg->mode == IA_CSS_INPUT_MODE_SENSOR ||
 944             stream_cfg->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) &&
 945            stream_cfg->source.port.compression.type != IA_CSS_CSI2_COMPRESSION_TYPE_NONE) {
 946                if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
 947                    UNCOMPRESSED_BITS_PER_PIXEL_10)
 948                        fmt_type = ATOMISP_INPUT_FORMAT_RAW_10;
 949                else if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
 950                           UNCOMPRESSED_BITS_PER_PIXEL_12)
 951                        fmt_type = ATOMISP_INPUT_FORMAT_RAW_12;
 952                else
 953                        return false;
 954        }
 955
 956        bits_per_subpixel =
 957            sh_css_stream_format_2_bits_per_subpixel(fmt_type);
 958        if (bits_per_subpixel == 0)
 959                return false;
 960
 961        max_subpixels_per_line =
 962            csi2_protocol_calculate_max_subpixels_per_line(fmt_type,
 963                    stream_cfg->isys_config[isys_stream_idx].input_res.width);
 964        if (max_subpixels_per_line == 0)
 965                return false;
 966
 967        lines_per_frame = stream_cfg->isys_config[isys_stream_idx].input_res.height;
 968        if (lines_per_frame == 0)
 969                return false;
 970
 971        align_req_in_bytes = ia_css_csi2_calculate_input_system_alignment(fmt_type);
 972
 973        /* HW needs subpixel info for their settings */
 974        isys_stream_descr->input_port_resolution.bits_per_pixel = bits_per_subpixel;
 975        isys_stream_descr->input_port_resolution.pixels_per_line =
 976            max_subpixels_per_line;
 977        isys_stream_descr->input_port_resolution.lines_per_frame = lines_per_frame;
 978        isys_stream_descr->input_port_resolution.align_req_in_bytes =
 979            align_req_in_bytes;
 980
 981        return true;
 982}
 983
 984static bool sh_css_translate_stream_cfg_to_isys_stream_descr(
 985    struct ia_css_stream_config *stream_cfg,
 986    bool early_polling,
 987    ia_css_isys_descr_t *isys_stream_descr,
 988    int isys_stream_idx)
 989{
 990        bool rc;
 991
 992        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
 993                            "sh_css_translate_stream_cfg_to_isys_stream_descr() enter:\n");
 994        rc  = sh_css_translate_stream_cfg_to_input_system_input_port_id(stream_cfg,
 995                isys_stream_descr);
 996        rc &= sh_css_translate_stream_cfg_to_input_system_input_port_type(stream_cfg,
 997                isys_stream_descr);
 998        rc &= sh_css_translate_stream_cfg_to_input_system_input_port_attr(stream_cfg,
 999                isys_stream_descr, isys_stream_idx);
1000        rc &= sh_css_translate_stream_cfg_to_input_system_input_port_resolution(
1001                  stream_cfg, isys_stream_descr, isys_stream_idx);
1002
1003        isys_stream_descr->raw_packed = stream_cfg->pack_raw_pixels;
1004        isys_stream_descr->linked_isys_stream_id = (int8_t)
1005                stream_cfg->isys_config[isys_stream_idx].linked_isys_stream_id;
1006        /*
1007         * Early polling is required for timestamp accuracy in certain case.
1008         * The ISYS HW polling is started on
1009         * ia_css_isys_stream_capture_indication() instead of
1010         * ia_css_pipeline_sp_wait_for_isys_stream_N() as isp processing of
1011         * capture takes longer than getting an ISYS frame
1012         *
1013         * Only 2401 relevant ??
1014         */
1015#if 0 // FIXME: NOT USED on Yocto Aero
1016        isys_stream_descr->polling_mode
1017            = early_polling ? INPUT_SYSTEM_POLL_ON_CAPTURE_REQUEST
1018              : INPUT_SYSTEM_POLL_ON_WAIT_FOR_FRAME;
1019        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
1020                            "sh_css_translate_stream_cfg_to_isys_stream_descr() leave:\n");
1021#endif
1022
1023        return rc;
1024}
1025
1026static bool sh_css_translate_binary_info_to_input_system_output_port_attr(
1027    struct ia_css_binary *binary,
1028    ia_css_isys_descr_t     *isys_stream_descr)
1029{
1030        if (!binary)
1031                return false;
1032
1033        isys_stream_descr->output_port_attr.left_padding = binary->left_padding;
1034        isys_stream_descr->output_port_attr.max_isp_input_width =
1035            binary->info->sp.input.max_width;
1036
1037        return true;
1038}
1039
1040static int
1041sh_css_config_input_network(struct ia_css_stream *stream)
1042{
1043        bool                                    rc;
1044        ia_css_isys_descr_t                     isys_stream_descr;
1045        unsigned int                            sp_thread_id;
1046        struct sh_css_sp_pipeline_terminal      *sp_pipeline_input_terminal;
1047        struct ia_css_pipe *pipe = NULL;
1048        struct ia_css_binary *binary = NULL;
1049        int i;
1050        u32 isys_stream_id;
1051        bool early_polling = false;
1052
1053        assert(stream);
1054        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
1055                            "sh_css_config_input_network() enter 0x%p:\n", stream);
1056
1057        if (stream->config.continuous) {
1058                if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE)
1059                        pipe = stream->last_pipe;
1060                else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_YUVPP)
1061                        pipe = stream->last_pipe;
1062                else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
1063                        pipe = stream->last_pipe->pipe_settings.preview.copy_pipe;
1064                else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO)
1065                        pipe = stream->last_pipe->pipe_settings.video.copy_pipe;
1066        } else {
1067                pipe = stream->last_pipe;
1068                if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
1069                        /*
1070                         * We need to poll the ISYS HW in capture_indication itself
1071                         * for "non-continuous" capture usecase for getting accurate
1072                         * isys frame capture timestamps.
1073                         * This is because the capturepipe propcessing takes longer
1074                         * to execute than the input system frame capture.
1075                         * 2401 specific
1076                         */
1077                        early_polling = true;
1078                }
1079        }
1080
1081        if (!pipe)
1082                return -EINVAL;
1083
1084        if (pipe->pipeline.stages)
1085                if (pipe->pipeline.stages->binary)
1086                        binary = pipe->pipeline.stages->binary;
1087
1088        if (binary) {
1089                /* this was being done in ifmtr in 2400.
1090                 * online and cont bypass the init_in_frameinfo_memory_defaults
1091                 * so need to do it here
1092                 */
1093                ia_css_get_crop_offsets(pipe, &binary->in_frame_info);
1094        }
1095
1096        /* get the SP thread id */
1097        rc = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &sp_thread_id);
1098        if (!rc)
1099                return -EINVAL;
1100        /* get the target input terminal */
1101        sp_pipeline_input_terminal = &sh_css_sp_group.pipe_io[sp_thread_id].input;
1102
1103        for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) {
1104                /* initialization */
1105                memset((void *)(&isys_stream_descr), 0, sizeof(ia_css_isys_descr_t));
1106                sp_pipeline_input_terminal->context.virtual_input_system_stream[i].valid = 0;
1107                sp_pipeline_input_terminal->ctrl.virtual_input_system_stream_cfg[i].valid = 0;
1108
1109                if (!stream->config.isys_config[i].valid)
1110                        continue;
1111
1112                /* translate the stream configuration to the Input System (2401) configuration */
1113                rc = sh_css_translate_stream_cfg_to_isys_stream_descr(
1114                         &stream->config,
1115                         early_polling,
1116                         &(isys_stream_descr), i);
1117
1118                if (stream->config.online) {
1119                        rc &= sh_css_translate_binary_info_to_input_system_output_port_attr(
1120                                  binary,
1121                                  &(isys_stream_descr));
1122                }
1123
1124                if (!rc)
1125                        return -EINVAL;
1126
1127                isys_stream_id = ia_css_isys_generate_stream_id(sp_thread_id, i);
1128
1129                /* create the virtual Input System (2401) */
1130                rc =  ia_css_isys_stream_create(
1131                          &(isys_stream_descr),
1132                          &sp_pipeline_input_terminal->context.virtual_input_system_stream[i],
1133                          isys_stream_id);
1134                if (!rc)
1135                        return -EINVAL;
1136
1137                /* calculate the configuration of the virtual Input System (2401) */
1138                rc = ia_css_isys_stream_calculate_cfg(
1139                         &sp_pipeline_input_terminal->context.virtual_input_system_stream[i],
1140                         &(isys_stream_descr),
1141                         &sp_pipeline_input_terminal->ctrl.virtual_input_system_stream_cfg[i]);
1142                if (!rc) {
1143                        ia_css_isys_stream_destroy(
1144                            &sp_pipeline_input_terminal->context.virtual_input_system_stream[i]);
1145                        return -EINVAL;
1146                }
1147        }
1148
1149        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
1150                            "sh_css_config_input_network() leave:\n");
1151
1152        return 0;
1153}
1154
1155static inline struct ia_css_pipe *stream_get_last_pipe(
1156    struct ia_css_stream *stream)
1157{
1158        struct ia_css_pipe *last_pipe = NULL;
1159
1160        if (stream)
1161                last_pipe = stream->last_pipe;
1162
1163        return last_pipe;
1164}
1165
1166static inline struct ia_css_pipe *stream_get_copy_pipe(
1167    struct ia_css_stream *stream)
1168{
1169        struct ia_css_pipe *copy_pipe = NULL;
1170        struct ia_css_pipe *last_pipe = NULL;
1171        enum ia_css_pipe_id pipe_id;
1172
1173        last_pipe = stream_get_last_pipe(stream);
1174
1175        if ((stream) &&
1176            (last_pipe) &&
1177            (stream->config.continuous)) {
1178                pipe_id = last_pipe->mode;
1179                switch (pipe_id) {
1180                case IA_CSS_PIPE_ID_PREVIEW:
1181                        copy_pipe = last_pipe->pipe_settings.preview.copy_pipe;
1182                        break;
1183                case IA_CSS_PIPE_ID_VIDEO:
1184                        copy_pipe = last_pipe->pipe_settings.video.copy_pipe;
1185                        break;
1186                default:
1187                        copy_pipe = NULL;
1188                        break;
1189                }
1190        }
1191
1192        return copy_pipe;
1193}
1194
1195static inline struct ia_css_pipe *stream_get_target_pipe(
1196    struct ia_css_stream *stream)
1197{
1198        struct ia_css_pipe *target_pipe;
1199
1200        /* get the pipe that consumes the stream */
1201        if (stream->config.continuous)
1202                target_pipe = stream_get_copy_pipe(stream);
1203        else
1204                target_pipe = stream_get_last_pipe(stream);
1205
1206        return target_pipe;
1207}
1208
1209static int stream_csi_rx_helper(
1210    struct ia_css_stream *stream,
1211    int (*func)(enum mipi_port_id, uint32_t))
1212{
1213        int retval = -EINVAL;
1214        u32 sp_thread_id, stream_id;
1215        bool rc;
1216        struct ia_css_pipe *target_pipe = NULL;
1217
1218        if ((!stream) || (stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR))
1219                goto exit;
1220
1221        target_pipe = stream_get_target_pipe(stream);
1222
1223        if (!target_pipe)
1224                goto exit;
1225
1226        rc = ia_css_pipeline_get_sp_thread_id(
1227                 ia_css_pipe_get_pipe_num(target_pipe),
1228                 &sp_thread_id);
1229
1230        if (!rc)
1231                goto exit;
1232
1233        /* (un)register all valid "virtual isys streams" within the ia_css_stream */
1234        stream_id = 0;
1235        do {
1236                if (stream->config.isys_config[stream_id].valid) {
1237                        u32 isys_stream_id = ia_css_isys_generate_stream_id(sp_thread_id, stream_id);
1238
1239                        retval = func(stream->config.source.port.port, isys_stream_id);
1240                }
1241                stream_id++;
1242        } while ((retval == 0) &&
1243                 (stream_id < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH));
1244
1245exit:
1246        return retval;
1247}
1248
1249static inline int stream_register_with_csi_rx(
1250    struct ia_css_stream *stream)
1251{
1252        return stream_csi_rx_helper(stream, ia_css_isys_csi_rx_register_stream);
1253}
1254
1255static inline int stream_unregister_with_csi_rx(
1256    struct ia_css_stream *stream)
1257{
1258        return stream_csi_rx_helper(stream, ia_css_isys_csi_rx_unregister_stream);
1259}
1260#endif
1261
1262#if WITH_PC_MONITORING
1263static struct task_struct *my_kthread;    /* Handle for the monitoring thread */
1264static int sh_binary_running;         /* Enable sampling in the thread */
1265
1266static void print_pc_histo(char *core_name, struct sh_css_pc_histogram *hist)
1267{
1268        unsigned int i;
1269        unsigned int cnt_run = 0;
1270        unsigned int cnt_stall = 0;
1271
1272        if (!hist)
1273                return;
1274
1275        sh_css_print("%s histogram length = %d\n", core_name, hist->length);
1276        sh_css_print("%s PC\turn\tstall\n", core_name);
1277
1278        for (i = 0; i < hist->length; i++) {
1279                if ((hist->run[i] == 0) && (hist->run[i] == hist->stall[i]))
1280                        continue;
1281                sh_css_print("%s %d\t%d\t%d\n",
1282                             core_name, i, hist->run[i], hist->stall[i]);
1283                cnt_run += hist->run[i];
1284                cnt_stall += hist->stall[i];
1285        }
1286
1287        sh_css_print(" Statistics for %s, cnt_run = %d, cnt_stall = %d, hist->length = %d\n",
1288                     core_name, cnt_run, cnt_stall, hist->length);
1289}
1290
1291static void print_pc_histogram(void)
1292{
1293        struct ia_css_binary_metrics *metrics;
1294
1295        for (metrics = sh_css_metrics.binary_metrics;
1296             metrics;
1297             metrics = metrics->next) {
1298                if (metrics->mode == IA_CSS_BINARY_MODE_PREVIEW ||
1299                    metrics->mode == IA_CSS_BINARY_MODE_VF_PP) {
1300                        sh_css_print("pc_histogram for binary %d is SKIPPED\n",
1301                                     metrics->id);
1302                        continue;
1303                }
1304
1305                sh_css_print(" pc_histogram for binary %d\n", metrics->id);
1306                print_pc_histo("  ISP", &metrics->isp_histogram);
1307                print_pc_histo("  SP",   &metrics->sp_histogram);
1308                sh_css_print("print_pc_histogram() done for binary->id = %d, done.\n",
1309                             metrics->id);
1310        }
1311
1312        sh_css_print("PC_MONITORING:print_pc_histogram() -- DONE\n");
1313}
1314
1315static int pc_monitoring(void *data)
1316{
1317        int i = 0;
1318
1319        (void)data;
1320        while (true) {
1321                if (sh_binary_running) {
1322                        sh_css_metrics_sample_pcs();
1323#if MULTIPLE_SAMPLES
1324                        for (i = 0; i < NOF_SAMPLES; i++)
1325                                sh_css_metrics_sample_pcs();
1326#endif
1327                }
1328                usleep_range(10, 50);
1329        }
1330        return 0;
1331}
1332
1333static void spying_thread_create(void)
1334{
1335        my_kthread = kthread_run(pc_monitoring, NULL, "sh_pc_monitor");
1336        sh_css_metrics_enable_pc_histogram(1);
1337}
1338
1339static void input_frame_info(struct ia_css_frame_info frame_info)
1340{
1341        sh_css_print("SH_CSS:input_frame_info() -- frame->info.res.width = %d, frame->info.res.height = %d, format = %d\n",
1342                     frame_info.res.width, frame_info.res.height, frame_info.format);
1343}
1344#endif /* WITH_PC_MONITORING */
1345
1346static void
1347start_binary(struct ia_css_pipe *pipe,
1348             struct ia_css_binary *binary)
1349{
1350        assert(pipe);
1351        /* Acceleration uses firmware, the binary thus can be NULL */
1352
1353        if (binary)
1354                sh_css_metrics_start_binary(&binary->metrics);
1355
1356#if WITH_PC_MONITORING
1357        sh_css_print("PC_MONITORING: %s() -- binary id = %d , enable_dvs_envelope = %d\n",
1358                     __func__, binary->info->sp.id,
1359                     binary->info->sp.enable.dvs_envelope);
1360        input_frame_info(binary->in_frame_info);
1361
1362        if (binary && binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_VIDEO)
1363                sh_binary_running = true;
1364#endif
1365
1366#if !defined(ISP2401)
1367        if (pipe->stream->reconfigure_css_rx) {
1368                ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
1369                                         pipe->stream->config.mode);
1370                pipe->stream->reconfigure_css_rx = false;
1371        }
1372#endif
1373}
1374
1375/* start the copy function on the SP */
1376static int
1377start_copy_on_sp(struct ia_css_pipe *pipe,
1378                 struct ia_css_frame *out_frame)
1379{
1380        (void)out_frame;
1381
1382        if ((!pipe) || (!pipe->stream))
1383                return -EINVAL;
1384
1385#if !defined(ISP2401)
1386        if (pipe->stream->reconfigure_css_rx)
1387                ia_css_isys_rx_disable();
1388#endif
1389
1390        if (pipe->stream->config.input_config.format != ATOMISP_INPUT_FORMAT_BINARY_8)
1391                return -EINVAL;
1392        sh_css_sp_start_binary_copy(ia_css_pipe_get_pipe_num(pipe), out_frame, pipe->stream->config.pixels_per_clock == 2);
1393
1394#if !defined(ISP2401)
1395        if (pipe->stream->reconfigure_css_rx) {
1396                ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
1397                                         pipe->stream->config.mode);
1398                pipe->stream->reconfigure_css_rx = false;
1399        }
1400#endif
1401
1402        return 0;
1403}
1404
1405void sh_css_binary_args_reset(struct sh_css_binary_args *args)
1406{
1407        unsigned int i;
1408
1409        for (i = 0; i < NUM_TNR_FRAMES; i++)
1410                args->tnr_frames[i] = NULL;
1411        for (i = 0; i < MAX_NUM_VIDEO_DELAY_FRAMES; i++)
1412                args->delay_frames[i] = NULL;
1413        args->in_frame      = NULL;
1414        for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++)
1415                args->out_frame[i] = NULL;
1416        args->out_vf_frame  = NULL;
1417        args->copy_vf       = false;
1418        args->copy_output   = true;
1419        args->vf_downscale_log2 = 0;
1420}
1421
1422static void start_pipe(
1423    struct ia_css_pipe *me,
1424    enum sh_css_pipe_config_override copy_ovrd,
1425    enum ia_css_input_mode input_mode)
1426{
1427        const struct ia_css_coordinate *coord = NULL;
1428        const struct ia_css_isp_parameters *params = NULL;
1429
1430
1431        IA_CSS_ENTER_PRIVATE("me = %p, copy_ovrd = %d, input_mode = %d",
1432                             me, copy_ovrd, input_mode);
1433
1434        assert(me); /* all callers are in this file and call with non null argument */
1435
1436        if (!IS_ISP2401) {
1437                coord = &me->config.internal_frame_origin_bqs_on_sctbl;
1438                params = me->stream->isp_params_configs;
1439        }
1440
1441        sh_css_sp_init_pipeline(&me->pipeline,
1442                                me->mode,
1443                                (uint8_t)ia_css_pipe_get_pipe_num(me),
1444                                me->config.default_capture_config.enable_xnr != 0,
1445                                me->stream->config.pixels_per_clock == 2,
1446                                me->stream->config.continuous,
1447                                false,
1448                                me->required_bds_factor,
1449                                copy_ovrd,
1450                                input_mode,
1451                                &me->stream->config.metadata_config,
1452                                &me->stream->info.metadata_info
1453                                , (input_mode == IA_CSS_INPUT_MODE_MEMORY) ?
1454                                (enum mipi_port_id)0 :
1455                                me->stream->config.source.port.port,
1456                                coord,
1457                                params);
1458
1459        if (me->config.mode != IA_CSS_PIPE_MODE_COPY) {
1460                struct ia_css_pipeline_stage *stage;
1461
1462                stage = me->pipeline.stages;
1463                if (stage) {
1464                        me->pipeline.current_stage = stage;
1465                        start_binary(me, stage->binary);
1466                }
1467        }
1468        IA_CSS_LEAVE_PRIVATE("void");
1469}
1470
1471void
1472sh_css_invalidate_shading_tables(struct ia_css_stream *stream)
1473{
1474        int i;
1475
1476        assert(stream);
1477
1478        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1479                            "sh_css_invalidate_shading_tables() enter:\n");
1480
1481        for (i = 0; i < stream->num_pipes; i++) {
1482                assert(stream->pipes[i]);
1483                sh_css_pipe_free_shading_table(stream->pipes[i]);
1484        }
1485
1486        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1487                            "sh_css_invalidate_shading_tables() leave: return_void\n");
1488}
1489
1490static void
1491enable_interrupts(enum ia_css_irq_type irq_type)
1492{
1493#ifndef ISP2401
1494        enum mipi_port_id port;
1495#endif
1496        bool enable_pulse = irq_type != IA_CSS_IRQ_TYPE_EDGE;
1497
1498        IA_CSS_ENTER_PRIVATE("");
1499        /* Enable IRQ on the SP which signals that SP goes to idle
1500         * (aka ready state) */
1501        cnd_sp_irq_enable(SP0_ID, true);
1502        /* Set the IRQ device 0 to either level or pulse */
1503        irq_enable_pulse(IRQ0_ID, enable_pulse);
1504
1505        cnd_virq_enable_channel(virq_sp, true);
1506
1507        /* Enable SW interrupt 0, this is used to signal ISYS events */
1508        cnd_virq_enable_channel(
1509            (enum virq_id)(IRQ_SW_CHANNEL0_ID + IRQ_SW_CHANNEL_OFFSET),
1510            true);
1511        /* Enable SW interrupt 1, this is used to signal PSYS events */
1512        cnd_virq_enable_channel(
1513            (enum virq_id)(IRQ_SW_CHANNEL1_ID + IRQ_SW_CHANNEL_OFFSET),
1514            true);
1515
1516#ifndef ISP2401
1517        for (port = 0; port < N_MIPI_PORT_ID; port++)
1518                ia_css_isys_rx_enable_all_interrupts(port);
1519#endif
1520
1521        IA_CSS_LEAVE_PRIVATE("");
1522}
1523
1524static bool sh_css_setup_spctrl_config(const struct ia_css_fw_info *fw,
1525                                       const char *program,
1526                                       ia_css_spctrl_cfg  *spctrl_cfg)
1527{
1528        if ((!fw) || (!spctrl_cfg))
1529                return false;
1530        spctrl_cfg->sp_entry = 0;
1531        spctrl_cfg->program_name = (char *)(program);
1532
1533        spctrl_cfg->ddr_data_offset =  fw->blob.data_source;
1534        spctrl_cfg->dmem_data_addr = fw->blob.data_target;
1535        spctrl_cfg->dmem_bss_addr = fw->blob.bss_target;
1536        spctrl_cfg->data_size = fw->blob.data_size;
1537        spctrl_cfg->bss_size = fw->blob.bss_size;
1538
1539        spctrl_cfg->spctrl_config_dmem_addr = fw->info.sp.init_dmem_data;
1540        spctrl_cfg->spctrl_state_dmem_addr = fw->info.sp.sw_state;
1541
1542        spctrl_cfg->code_size = fw->blob.size;
1543        spctrl_cfg->code      = fw->blob.code;
1544        spctrl_cfg->sp_entry  = fw->info.sp.sp_entry; /* entry function ptr on SP */
1545
1546        return true;
1547}
1548
1549void
1550ia_css_unload_firmware(void)
1551{
1552        if (sh_css_num_binaries) {
1553                /* we have already loaded before so get rid of the old stuff */
1554                ia_css_binary_uninit();
1555                sh_css_unload_firmware();
1556        }
1557        fw_explicitly_loaded = false;
1558}
1559
1560static void
1561ia_css_reset_defaults(struct sh_css *css)
1562{
1563        struct sh_css default_css;
1564
1565        /* Reset everything to zero */
1566        memset(&default_css, 0, sizeof(default_css));
1567
1568        /* Initialize the non zero values*/
1569        default_css.check_system_idle = true;
1570        default_css.num_cont_raw_frames = NUM_CONTINUOUS_FRAMES;
1571
1572        /* All should be 0: but memset does it already.
1573         * default_css.num_mipi_frames[N_CSI_PORTS] = 0;
1574         */
1575
1576        default_css.irq_type = IA_CSS_IRQ_TYPE_EDGE;
1577
1578        /*Set the defaults to the output */
1579        *css = default_css;
1580}
1581
1582int
1583ia_css_load_firmware(struct device *dev, const struct ia_css_env *env,
1584                     const struct ia_css_fw  *fw)
1585{
1586        int err;
1587
1588        if (!env)
1589                return -EINVAL;
1590        if (!fw)
1591                return -EINVAL;
1592
1593        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() enter\n");
1594
1595        /* make sure we initialize my_css */
1596        if (my_css.flush != env->cpu_mem_env.flush) {
1597                ia_css_reset_defaults(&my_css);
1598                my_css.flush = env->cpu_mem_env.flush;
1599        }
1600
1601        ia_css_unload_firmware(); /* in case we are called twice */
1602        err = sh_css_load_firmware(dev, fw->data, fw->bytes);
1603        if (!err) {
1604                err = ia_css_binary_init_infos();
1605                if (!err)
1606                        fw_explicitly_loaded = true;
1607        }
1608
1609        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() leave\n");
1610        return err;
1611}
1612
1613int
1614ia_css_init(struct device *dev, const struct ia_css_env *env,
1615            const struct ia_css_fw  *fw,
1616            u32                 mmu_l1_base,
1617            enum ia_css_irq_type     irq_type)
1618{
1619        int err;
1620        ia_css_spctrl_cfg spctrl_cfg;
1621
1622        void (*flush_func)(struct ia_css_acc_fw *fw);
1623        hrt_data select, enable;
1624
1625        /*
1626         * The C99 standard does not specify the exact object representation of structs;
1627         * the representation is compiler dependent.
1628         *
1629         * The structs that are communicated between host and SP/ISP should have the
1630         * exact same object representation. The compiler that is used to compile the
1631         * firmware is hivecc.
1632         *
1633         * To check if a different compiler, used to compile a host application, uses
1634         * another object representation, macros are defined specifying the size of
1635         * the structs as expected by the firmware.
1636         *
1637         * A host application shall verify that a sizeof( ) of the struct is equal to
1638         * the SIZE_OF_XXX macro of the corresponding struct. If they are not
1639         * equal, functionality will break.
1640         */
1641        /* Check struct sh_css_ddr_address_map */
1642        COMPILATION_ERROR_IF(sizeof(struct sh_css_ddr_address_map)              != SIZE_OF_SH_CSS_DDR_ADDRESS_MAP_STRUCT);
1643        /* Check struct host_sp_queues */
1644        COMPILATION_ERROR_IF(sizeof(struct host_sp_queues)                      != SIZE_OF_HOST_SP_QUEUES_STRUCT);
1645        COMPILATION_ERROR_IF(sizeof(struct ia_css_circbuf_desc_s)               != SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT);
1646        COMPILATION_ERROR_IF(sizeof(struct ia_css_circbuf_elem_s)               != SIZE_OF_IA_CSS_CIRCBUF_ELEM_S_STRUCT);
1647
1648        /* Check struct host_sp_communication */
1649        COMPILATION_ERROR_IF(sizeof(struct host_sp_communication)               != SIZE_OF_HOST_SP_COMMUNICATION_STRUCT);
1650        COMPILATION_ERROR_IF(sizeof(struct sh_css_event_irq_mask)               != SIZE_OF_SH_CSS_EVENT_IRQ_MASK_STRUCT);
1651
1652        /* Check struct sh_css_hmm_buffer */
1653        COMPILATION_ERROR_IF(sizeof(struct sh_css_hmm_buffer)                   != SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT);
1654        COMPILATION_ERROR_IF(sizeof(struct ia_css_isp_3a_statistics)            != SIZE_OF_IA_CSS_ISP_3A_STATISTICS_STRUCT);
1655        COMPILATION_ERROR_IF(sizeof(struct ia_css_isp_dvs_statistics)           != SIZE_OF_IA_CSS_ISP_DVS_STATISTICS_STRUCT);
1656        COMPILATION_ERROR_IF(sizeof(struct ia_css_metadata)                     != SIZE_OF_IA_CSS_METADATA_STRUCT);
1657
1658        /* Check struct ia_css_init_dmem_cfg */
1659        COMPILATION_ERROR_IF(sizeof(struct ia_css_sp_init_dmem_cfg)             != SIZE_OF_IA_CSS_SP_INIT_DMEM_CFG_STRUCT);
1660
1661        if (!fw && !fw_explicitly_loaded)
1662                return -EINVAL;
1663        if (!env)
1664                return -EINVAL;
1665
1666        sh_css_printf = env->print_env.debug_print;
1667
1668        IA_CSS_ENTER("void");
1669
1670        flush_func     = env->cpu_mem_env.flush;
1671
1672        pipe_global_init();
1673        ia_css_pipeline_init();
1674        ia_css_queue_map_init();
1675
1676        ia_css_device_access_init(&env->hw_access_env);
1677
1678        select = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_select)
1679        & (~GPIO_FLASH_PIN_MASK);
1680        enable = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_e)
1681        | GPIO_FLASH_PIN_MASK;
1682        sh_css_mmu_set_page_table_base_index(mmu_l1_base);
1683
1684        my_css_save.mmu_base = mmu_l1_base;
1685
1686        ia_css_reset_defaults(&my_css);
1687
1688        my_css_save.driver_env = *env;
1689        my_css.flush     = flush_func;
1690
1691        err = ia_css_rmgr_init();
1692        if (err) {
1693                IA_CSS_LEAVE_ERR(err);
1694                return err;
1695        }
1696
1697        IA_CSS_LOG("init: %d", my_css_save_initialized);
1698
1699        if (!my_css_save_initialized) {
1700                my_css_save_initialized = true;
1701                my_css_save.mode = sh_css_mode_working;
1702                memset(my_css_save.stream_seeds, 0,
1703                       sizeof(struct sh_css_stream_seed) * MAX_ACTIVE_STREAMS);
1704                IA_CSS_LOG("init: %d mode=%d", my_css_save_initialized, my_css_save.mode);
1705        }
1706
1707        mipi_init();
1708
1709#ifndef ISP2401
1710        /* In case this has been programmed already, update internal
1711           data structure ... DEPRECATED */
1712        my_css.page_table_base_index = mmu_get_page_table_base_index(MMU0_ID);
1713
1714#endif
1715        my_css.irq_type = irq_type;
1716
1717        my_css_save.irq_type = irq_type;
1718
1719        enable_interrupts(my_css.irq_type);
1720
1721        /* configure GPIO to output mode */
1722        gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_select, select);
1723        gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_e, enable);
1724        gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_0, 0);
1725
1726        err = ia_css_refcount_init(REFCOUNT_SIZE);
1727        if (err) {
1728                IA_CSS_LEAVE_ERR(err);
1729                return err;
1730        }
1731        err = sh_css_params_init();
1732        if (err) {
1733                IA_CSS_LEAVE_ERR(err);
1734                return err;
1735        }
1736        if (fw) {
1737                ia_css_unload_firmware(); /* in case we already had firmware loaded */
1738                err = sh_css_load_firmware(dev, fw->data, fw->bytes);
1739                if (err) {
1740                        IA_CSS_LEAVE_ERR(err);
1741                        return err;
1742                }
1743                err = ia_css_binary_init_infos();
1744                if (err) {
1745                        IA_CSS_LEAVE_ERR(err);
1746                        return err;
1747                }
1748                fw_explicitly_loaded = false;
1749#ifndef ISP2401
1750                my_css_save.loaded_fw = (struct ia_css_fw *)fw;
1751#endif
1752        }
1753        if (!sh_css_setup_spctrl_config(&sh_css_sp_fw, SP_PROG_NAME, &spctrl_cfg))
1754                return -EINVAL;
1755
1756        err = ia_css_spctrl_load_fw(SP0_ID, &spctrl_cfg);
1757        if (err) {
1758                IA_CSS_LEAVE_ERR(err);
1759                return err;
1760        }
1761
1762#if WITH_PC_MONITORING
1763        if (!thread_alive) {
1764                thread_alive++;
1765                sh_css_print("PC_MONITORING: %s() -- create thread DISABLED\n",
1766                             __func__);
1767                spying_thread_create();
1768        }
1769#endif
1770        if (!sh_css_hrt_system_is_idle()) {
1771                IA_CSS_LEAVE_ERR(-EBUSY);
1772                return -EBUSY;
1773        }
1774        /* can be called here, queuing works, but:
1775           - when sp is started later, it will wipe queued items
1776           so for now we leave it for later and make sure
1777           updates are not called to frequently.
1778        sh_css_init_buffer_queues();
1779        */
1780
1781#if defined(ISP2401)
1782        gp_device_reg_store(GP_DEVICE0_ID, _REG_GP_SWITCH_ISYS2401_ADDR, 1);
1783#endif
1784
1785
1786        if (!IS_ISP2401)
1787                dma_set_max_burst_size(DMA0_ID, HIVE_DMA_BUS_DDR_CONN,
1788                                       ISP2400_DMA_MAX_BURST_LENGTH);
1789        else
1790                dma_set_max_burst_size(DMA0_ID, HIVE_DMA_BUS_DDR_CONN,
1791                                       ISP2401_DMA_MAX_BURST_LENGTH);
1792
1793        if (ia_css_isys_init() != INPUT_SYSTEM_ERR_NO_ERROR)
1794                err = -EINVAL;
1795
1796        sh_css_params_map_and_store_default_gdc_lut();
1797
1798        IA_CSS_LEAVE_ERR(err);
1799        return err;
1800}
1801
1802int
1803ia_css_enable_isys_event_queue(bool enable)
1804{
1805        if (sh_css_sp_is_running())
1806                return -EBUSY;
1807        sh_css_sp_enable_isys_event_queue(enable);
1808        return 0;
1809}
1810
1811/* For Acceleration API: Flush FW (shared buffer pointer) arguments */
1812void
1813sh_css_flush(struct ia_css_acc_fw *fw)
1814{
1815        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "sh_css_flush() enter:\n");
1816        if ((fw) && (my_css.flush))
1817                my_css.flush(fw);
1818}
1819
1820/* Mapping sp threads. Currently, this is done when a stream is created and
1821 * pipelines are ready to be converted to sp pipelines. Be careful if you are
1822 * doing it from stream_create since we could run out of sp threads due to
1823 * allocation on inactive pipelines. */
1824static int
1825map_sp_threads(struct ia_css_stream *stream, bool map)
1826{
1827        struct ia_css_pipe *main_pipe = NULL;
1828        struct ia_css_pipe *copy_pipe = NULL;
1829        struct ia_css_pipe *capture_pipe = NULL;
1830        struct ia_css_pipe *acc_pipe = NULL;
1831        int err = 0;
1832        enum ia_css_pipe_id pipe_id;
1833
1834        IA_CSS_ENTER_PRIVATE("stream = %p, map = %s",
1835                             stream, map ? "true" : "false");
1836
1837        if (!stream) {
1838                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
1839                return -EINVAL;
1840        }
1841
1842        main_pipe = stream->last_pipe;
1843        pipe_id = main_pipe->mode;
1844
1845        ia_css_pipeline_map(main_pipe->pipe_num, map);
1846
1847        switch (pipe_id) {
1848        case IA_CSS_PIPE_ID_PREVIEW:
1849                copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
1850                capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
1851                acc_pipe     = main_pipe->pipe_settings.preview.acc_pipe;
1852                break;
1853
1854        case IA_CSS_PIPE_ID_VIDEO:
1855                copy_pipe    = main_pipe->pipe_settings.video.copy_pipe;
1856                capture_pipe = main_pipe->pipe_settings.video.capture_pipe;
1857                break;
1858
1859        case IA_CSS_PIPE_ID_CAPTURE:
1860        case IA_CSS_PIPE_ID_ACC:
1861        default:
1862                break;
1863        }
1864
1865        if (acc_pipe)
1866                ia_css_pipeline_map(acc_pipe->pipe_num, map);
1867
1868        if (capture_pipe)
1869                ia_css_pipeline_map(capture_pipe->pipe_num, map);
1870
1871        /* Firmware expects copy pipe to be the last pipe mapped. (if needed) */
1872        if (copy_pipe)
1873                ia_css_pipeline_map(copy_pipe->pipe_num, map);
1874
1875        /* DH regular multi pipe - not continuous mode: map the next pipes too */
1876        if (!stream->config.continuous) {
1877                int i;
1878
1879                for (i = 1; i < stream->num_pipes; i++)
1880                        ia_css_pipeline_map(stream->pipes[i]->pipe_num, map);
1881        }
1882
1883        IA_CSS_LEAVE_ERR_PRIVATE(err);
1884        return err;
1885}
1886
1887/* creates a host pipeline skeleton for all pipes in a stream. Called during
1888 * stream_create. */
1889static int
1890create_host_pipeline_structure(struct ia_css_stream *stream)
1891{
1892        struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
1893        struct ia_css_pipe *acc_pipe = NULL;
1894        enum ia_css_pipe_id pipe_id;
1895        struct ia_css_pipe *main_pipe = NULL;
1896        int err = 0;
1897        unsigned int copy_pipe_delay = 0,
1898        capture_pipe_delay = 0;
1899
1900        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
1901
1902        if (!stream) {
1903                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
1904                return -EINVAL;
1905        }
1906
1907        main_pipe       = stream->last_pipe;
1908        if (!main_pipe) {
1909                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
1910                return -EINVAL;
1911        }
1912
1913        pipe_id = main_pipe->mode;
1914
1915        switch (pipe_id) {
1916        case IA_CSS_PIPE_ID_PREVIEW:
1917                copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
1918                copy_pipe_delay = main_pipe->dvs_frame_delay;
1919                capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
1920                capture_pipe_delay = IA_CSS_FRAME_DELAY_0;
1921                acc_pipe     = main_pipe->pipe_settings.preview.acc_pipe;
1922                err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1923                                             main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1924                break;
1925
1926        case IA_CSS_PIPE_ID_VIDEO:
1927                copy_pipe    = main_pipe->pipe_settings.video.copy_pipe;
1928                copy_pipe_delay = main_pipe->dvs_frame_delay;
1929                capture_pipe = main_pipe->pipe_settings.video.capture_pipe;
1930                capture_pipe_delay = IA_CSS_FRAME_DELAY_0;
1931                err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1932                                             main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1933                break;
1934
1935        case IA_CSS_PIPE_ID_CAPTURE:
1936                capture_pipe = main_pipe;
1937                capture_pipe_delay = main_pipe->dvs_frame_delay;
1938                break;
1939
1940        case IA_CSS_PIPE_ID_YUVPP:
1941                err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1942                                             main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1943                break;
1944
1945        case IA_CSS_PIPE_ID_ACC:
1946                err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1947                                             main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1948                break;
1949
1950        default:
1951                err = -EINVAL;
1952        }
1953
1954        if (!(err) && copy_pipe)
1955                err = ia_css_pipeline_create(&copy_pipe->pipeline,
1956                                             copy_pipe->mode,
1957                                             copy_pipe->pipe_num,
1958                                             copy_pipe_delay);
1959
1960        if (!(err) && capture_pipe)
1961                err = ia_css_pipeline_create(&capture_pipe->pipeline,
1962                                             capture_pipe->mode,
1963                                             capture_pipe->pipe_num,
1964                                             capture_pipe_delay);
1965
1966        if (!(err) && acc_pipe)
1967                err = ia_css_pipeline_create(&acc_pipe->pipeline, acc_pipe->mode,
1968                                             acc_pipe->pipe_num, main_pipe->dvs_frame_delay);
1969
1970        /* DH regular multi pipe - not continuous mode: create the next pipelines too */
1971        if (!stream->config.continuous) {
1972                int i;
1973
1974                for (i = 1; i < stream->num_pipes && 0 == err; i++) {
1975                        main_pipe = stream->pipes[i];
1976                        err = ia_css_pipeline_create(&main_pipe->pipeline,
1977                                                     main_pipe->mode,
1978                                                     main_pipe->pipe_num,
1979                                                     main_pipe->dvs_frame_delay);
1980                }
1981        }
1982
1983        IA_CSS_LEAVE_ERR_PRIVATE(err);
1984        return err;
1985}
1986
1987/* creates a host pipeline for all pipes in a stream. Called during
1988 * stream_start. */
1989static int
1990create_host_pipeline(struct ia_css_stream *stream)
1991{
1992        struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
1993        struct ia_css_pipe *acc_pipe = NULL;
1994        enum ia_css_pipe_id pipe_id;
1995        struct ia_css_pipe *main_pipe = NULL;
1996        int err = 0;
1997        unsigned int max_input_width = 0;
1998
1999        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
2000        if (!stream) {
2001                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2002                return -EINVAL;
2003        }
2004
2005        main_pipe       = stream->last_pipe;
2006        pipe_id = main_pipe->mode;
2007
2008        /* No continuous frame allocation for capture pipe. It uses the
2009         * "main" pipe's frames. */
2010        if ((pipe_id == IA_CSS_PIPE_ID_PREVIEW) ||
2011            (pipe_id == IA_CSS_PIPE_ID_VIDEO)) {
2012                /* About pipe_id == IA_CSS_PIPE_ID_PREVIEW && stream->config.mode != IA_CSS_INPUT_MODE_MEMORY:
2013                 * The original condition pipe_id == IA_CSS_PIPE_ID_PREVIEW is too strong. E.g. in SkyCam (with memory
2014                 * based input frames) there is no continuous mode and thus no need for allocated continuous frames
2015                 * This is not only for SkyCam but for all preview cases that use DDR based input frames. For this
2016                 * reason the stream->config.mode != IA_CSS_INPUT_MODE_MEMORY has beed added.
2017                 */
2018                if (stream->config.continuous ||
2019                    (pipe_id == IA_CSS_PIPE_ID_PREVIEW &&
2020                     stream->config.mode != IA_CSS_INPUT_MODE_MEMORY)) {
2021                        err = alloc_continuous_frames(main_pipe, true);
2022                        if (err)
2023                                goto ERR;
2024                }
2025        }
2026
2027#if !defined(ISP2401)
2028        /* old isys: need to allocate_mipi_frames() even in IA_CSS_PIPE_MODE_COPY */
2029        if (pipe_id != IA_CSS_PIPE_ID_ACC) {
2030                err = allocate_mipi_frames(main_pipe, &stream->info);
2031                if (err)
2032                        goto ERR;
2033        }
2034#elif defined(ISP2401)
2035        if ((pipe_id != IA_CSS_PIPE_ID_ACC) &&
2036            (main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
2037                err = allocate_mipi_frames(main_pipe, &stream->info);
2038                if (err)
2039                        goto ERR;
2040        }
2041#endif
2042
2043        switch (pipe_id) {
2044        case IA_CSS_PIPE_ID_PREVIEW:
2045                copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
2046                capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
2047                acc_pipe     = main_pipe->pipe_settings.preview.acc_pipe;
2048                max_input_width =
2049                    main_pipe->pipe_settings.preview.preview_binary.info->sp.input.max_width;
2050
2051                err = create_host_preview_pipeline(main_pipe);
2052                if (err)
2053                        goto ERR;
2054
2055                break;
2056
2057        case IA_CSS_PIPE_ID_VIDEO:
2058                copy_pipe    = main_pipe->pipe_settings.video.copy_pipe;
2059                capture_pipe = main_pipe->pipe_settings.video.capture_pipe;
2060                max_input_width =
2061                    main_pipe->pipe_settings.video.video_binary.info->sp.input.max_width;
2062
2063                err = create_host_video_pipeline(main_pipe);
2064                if (err)
2065                        goto ERR;
2066
2067                break;
2068
2069        case IA_CSS_PIPE_ID_CAPTURE:
2070                capture_pipe = main_pipe;
2071
2072                break;
2073
2074        case IA_CSS_PIPE_ID_YUVPP:
2075                err = create_host_yuvpp_pipeline(main_pipe);
2076                if (err)
2077                        goto ERR;
2078
2079                break;
2080
2081        case IA_CSS_PIPE_ID_ACC:
2082                err = create_host_acc_pipeline(main_pipe);
2083                if (err)
2084                        goto ERR;
2085
2086                break;
2087        default:
2088                err = -EINVAL;
2089        }
2090        if (err)
2091                goto ERR;
2092
2093        if (copy_pipe) {
2094                err = create_host_copy_pipeline(copy_pipe, max_input_width,
2095                                                main_pipe->continuous_frames[0]);
2096                if (err)
2097                        goto ERR;
2098        }
2099
2100        if (capture_pipe) {
2101                err = create_host_capture_pipeline(capture_pipe);
2102                if (err)
2103                        goto ERR;
2104        }
2105
2106        if (acc_pipe) {
2107                err = create_host_acc_pipeline(acc_pipe);
2108                if (err)
2109                        goto ERR;
2110        }
2111
2112        /* DH regular multi pipe - not continuous mode: create the next pipelines too */
2113        if (!stream->config.continuous) {
2114                int i;
2115
2116                for (i = 1; i < stream->num_pipes && 0 == err; i++) {
2117                        switch (stream->pipes[i]->mode) {
2118                        case IA_CSS_PIPE_ID_PREVIEW:
2119                                err = create_host_preview_pipeline(stream->pipes[i]);
2120                                break;
2121                        case IA_CSS_PIPE_ID_VIDEO:
2122                                err = create_host_video_pipeline(stream->pipes[i]);
2123                                break;
2124                        case IA_CSS_PIPE_ID_CAPTURE:
2125                                err = create_host_capture_pipeline(stream->pipes[i]);
2126                                break;
2127                        case IA_CSS_PIPE_ID_YUVPP:
2128                                err = create_host_yuvpp_pipeline(stream->pipes[i]);
2129                                break;
2130                        case IA_CSS_PIPE_ID_ACC:
2131                                err = create_host_acc_pipeline(stream->pipes[i]);
2132                                break;
2133                        default:
2134                                err = -EINVAL;
2135                        }
2136                        if (err)
2137                                goto ERR;
2138                }
2139        }
2140
2141ERR:
2142        IA_CSS_LEAVE_ERR_PRIVATE(err);
2143        return err;
2144}
2145
2146static const struct ia_css_pipe default_pipe = IA_CSS_DEFAULT_PIPE;
2147static const struct ia_css_preview_settings preview = IA_CSS_DEFAULT_PREVIEW_SETTINGS;
2148static const struct ia_css_capture_settings capture = IA_CSS_DEFAULT_CAPTURE_SETTINGS;
2149static const struct ia_css_video_settings video = IA_CSS_DEFAULT_VIDEO_SETTINGS;
2150static const struct ia_css_yuvpp_settings yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS;
2151
2152static int
2153init_pipe_defaults(enum ia_css_pipe_mode mode,
2154                   struct ia_css_pipe *pipe,
2155                   bool copy_pipe)
2156{
2157        if (!pipe) {
2158                IA_CSS_ERROR("NULL pipe parameter");
2159                return -EINVAL;
2160        }
2161
2162        /* Initialize pipe to pre-defined defaults */
2163        memcpy(pipe, &default_pipe, sizeof(default_pipe));
2164
2165        /* TODO: JB should not be needed, but temporary backward reference */
2166        switch (mode) {
2167        case IA_CSS_PIPE_MODE_PREVIEW:
2168                pipe->mode = IA_CSS_PIPE_ID_PREVIEW;
2169                memcpy(&pipe->pipe_settings.preview, &preview, sizeof(preview));
2170                break;
2171        case IA_CSS_PIPE_MODE_CAPTURE:
2172                if (copy_pipe)
2173                        pipe->mode = IA_CSS_PIPE_ID_COPY;
2174                else
2175                        pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
2176
2177                memcpy(&pipe->pipe_settings.capture, &capture, sizeof(capture));
2178                break;
2179        case IA_CSS_PIPE_MODE_VIDEO:
2180                pipe->mode = IA_CSS_PIPE_ID_VIDEO;
2181                memcpy(&pipe->pipe_settings.video, &video, sizeof(video));
2182                break;
2183        case IA_CSS_PIPE_MODE_ACC:
2184                pipe->mode = IA_CSS_PIPE_ID_ACC;
2185                break;
2186        case IA_CSS_PIPE_MODE_COPY:
2187                pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
2188                break;
2189        case IA_CSS_PIPE_MODE_YUVPP:
2190                pipe->mode = IA_CSS_PIPE_ID_YUVPP;
2191                memcpy(&pipe->pipe_settings.yuvpp, &yuvpp, sizeof(yuvpp));
2192                break;
2193        default:
2194                return -EINVAL;
2195        }
2196
2197        return 0;
2198}
2199
2200static void
2201pipe_global_init(void)
2202{
2203        u8 i;
2204
2205        my_css.pipe_counter = 0;
2206        for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++)
2207                my_css.all_pipes[i] = NULL;
2208}
2209
2210static int
2211pipe_generate_pipe_num(const struct ia_css_pipe *pipe,
2212                       unsigned int *pipe_number)
2213{
2214        const u8 INVALID_PIPE_NUM = (uint8_t)~(0);
2215        u8 pipe_num = INVALID_PIPE_NUM;
2216        u8 i;
2217
2218        if (!pipe) {
2219                IA_CSS_ERROR("NULL pipe parameter");
2220                return -EINVAL;
2221        }
2222
2223        /* Assign a new pipe_num .... search for empty place */
2224        for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
2225                if (!my_css.all_pipes[i]) {
2226                        /*position is reserved */
2227                        my_css.all_pipes[i] = (struct ia_css_pipe *)pipe;
2228                        pipe_num = i;
2229                        break;
2230                }
2231        }
2232        if (pipe_num == INVALID_PIPE_NUM) {
2233                /* Max number of pipes already allocated */
2234                IA_CSS_ERROR("Max number of pipes already created");
2235                return -ENOSPC;
2236        }
2237
2238        my_css.pipe_counter++;
2239
2240        IA_CSS_LOG("pipe_num (%d)", pipe_num);
2241
2242        *pipe_number = pipe_num;
2243        return 0;
2244}
2245
2246static void
2247pipe_release_pipe_num(unsigned int pipe_num)
2248{
2249        my_css.all_pipes[pipe_num] = NULL;
2250        my_css.pipe_counter--;
2251        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2252                            "pipe_release_pipe_num (%d)\n", pipe_num);
2253}
2254
2255static int
2256create_pipe(enum ia_css_pipe_mode mode,
2257            struct ia_css_pipe **pipe,
2258            bool copy_pipe)
2259{
2260        int err = 0;
2261        struct ia_css_pipe *me;
2262
2263        if (!pipe) {
2264                IA_CSS_ERROR("NULL pipe parameter");
2265                return -EINVAL;
2266        }
2267
2268        me = kmalloc(sizeof(*me), GFP_KERNEL);
2269        if (!me)
2270                return -ENOMEM;
2271
2272        err = init_pipe_defaults(mode, me, copy_pipe);
2273        if (err) {
2274                kfree(me);
2275                return err;
2276        }
2277
2278        err = pipe_generate_pipe_num(me, &me->pipe_num);
2279        if (err) {
2280                kfree(me);
2281                return err;
2282        }
2283
2284        *pipe = me;
2285        return 0;
2286}
2287
2288struct ia_css_pipe *
2289find_pipe_by_num(uint32_t pipe_num)
2290{
2291        unsigned int i;
2292
2293        for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
2294                if (my_css.all_pipes[i] &&
2295                    ia_css_pipe_get_pipe_num(my_css.all_pipes[i]) == pipe_num) {
2296                        return my_css.all_pipes[i];
2297                }
2298        }
2299        return NULL;
2300}
2301
2302static void sh_css_pipe_free_acc_binaries(
2303    struct ia_css_pipe *pipe)
2304{
2305        struct ia_css_pipeline *pipeline;
2306        struct ia_css_pipeline_stage *stage;
2307
2308        if (!pipe) {
2309                IA_CSS_ERROR("NULL input pointer");
2310                return;
2311        }
2312        pipeline = &pipe->pipeline;
2313
2314        /* loop through the stages and unload them */
2315        for (stage = pipeline->stages; stage; stage = stage->next) {
2316                struct ia_css_fw_info *firmware = (struct ia_css_fw_info *)
2317                                                  stage->firmware;
2318                if (firmware)
2319                        ia_css_pipe_unload_extension(pipe, firmware);
2320        }
2321}
2322
2323int
2324ia_css_pipe_destroy(struct ia_css_pipe *pipe)
2325{
2326        int err = 0;
2327
2328        IA_CSS_ENTER("pipe = %p", pipe);
2329
2330        if (!pipe) {
2331                IA_CSS_LEAVE_ERR(-EINVAL);
2332                return -EINVAL;
2333        }
2334
2335        if (pipe->stream) {
2336                IA_CSS_LOG("ia_css_stream_destroy not called!");
2337                IA_CSS_LEAVE_ERR(-EINVAL);
2338                return -EINVAL;
2339        }
2340
2341        switch (pipe->config.mode) {
2342        case IA_CSS_PIPE_MODE_PREVIEW:
2343                /* need to take into account that this function is also called
2344                   on the internal copy pipe */
2345                if (pipe->mode == IA_CSS_PIPE_ID_PREVIEW) {
2346                        ia_css_frame_free_multiple(NUM_CONTINUOUS_FRAMES,
2347                                                   pipe->continuous_frames);
2348                        ia_css_metadata_free_multiple(NUM_CONTINUOUS_FRAMES,
2349                                                      pipe->cont_md_buffers);
2350                        if (pipe->pipe_settings.preview.copy_pipe) {
2351                                err = ia_css_pipe_destroy(pipe->pipe_settings.preview.copy_pipe);
2352                                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2353                                                    "ia_css_pipe_destroy(): destroyed internal copy pipe err=%d\n",
2354                                                    err);
2355                        }
2356                }
2357                break;
2358        case IA_CSS_PIPE_MODE_VIDEO:
2359                if (pipe->mode == IA_CSS_PIPE_ID_VIDEO) {
2360                        ia_css_frame_free_multiple(NUM_CONTINUOUS_FRAMES,
2361                                                   pipe->continuous_frames);
2362                        ia_css_metadata_free_multiple(NUM_CONTINUOUS_FRAMES,
2363                                                      pipe->cont_md_buffers);
2364                        if (pipe->pipe_settings.video.copy_pipe) {
2365                                err = ia_css_pipe_destroy(pipe->pipe_settings.video.copy_pipe);
2366                                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2367                                                    "ia_css_pipe_destroy(): destroyed internal copy pipe err=%d\n",
2368                                                    err);
2369                        }
2370                }
2371#ifndef ISP2401
2372                ia_css_frame_free_multiple(NUM_TNR_FRAMES,
2373                                           pipe->pipe_settings.video.tnr_frames);
2374#else
2375                ia_css_frame_free_multiple(NUM_TNR_FRAMES,
2376                                           pipe->pipe_settings.video.tnr_frames);
2377#endif
2378                ia_css_frame_free_multiple(MAX_NUM_VIDEO_DELAY_FRAMES,
2379                                           pipe->pipe_settings.video.delay_frames);
2380                break;
2381        case IA_CSS_PIPE_MODE_CAPTURE:
2382                ia_css_frame_free_multiple(MAX_NUM_VIDEO_DELAY_FRAMES,
2383                                           pipe->pipe_settings.capture.delay_frames);
2384                break;
2385        case IA_CSS_PIPE_MODE_ACC:
2386                sh_css_pipe_free_acc_binaries(pipe);
2387                break;
2388        case IA_CSS_PIPE_MODE_COPY:
2389                break;
2390        case IA_CSS_PIPE_MODE_YUVPP:
2391                break;
2392        }
2393
2394        sh_css_params_free_gdc_lut(pipe->scaler_pp_lut);
2395        pipe->scaler_pp_lut = mmgr_NULL;
2396
2397        my_css.active_pipes[ia_css_pipe_get_pipe_num(pipe)] = NULL;
2398        sh_css_pipe_free_shading_table(pipe);
2399
2400        ia_css_pipeline_destroy(&pipe->pipeline);
2401        pipe_release_pipe_num(ia_css_pipe_get_pipe_num(pipe));
2402
2403        /* Temporarily, not every sh_css_pipe has an acc_extension. */
2404        if (pipe->config.acc_extension)
2405                ia_css_pipe_unload_extension(pipe, pipe->config.acc_extension);
2406
2407        kfree(pipe);
2408        IA_CSS_LEAVE("err = %d", err);
2409        return err;
2410}
2411
2412void
2413ia_css_uninit(void)
2414{
2415        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_uninit() enter: void\n");
2416#if WITH_PC_MONITORING
2417        sh_css_print("PC_MONITORING: %s() -- started\n", __func__);
2418        print_pc_histogram();
2419#endif
2420
2421        sh_css_params_free_default_gdc_lut();
2422
2423        /* TODO: JB: implement decent check and handling of freeing mipi frames */
2424        //assert(ref_count_mipi_allocation == 0); //mipi frames are not freed
2425        /* cleanup generic data */
2426        sh_css_params_uninit();
2427        ia_css_refcount_uninit();
2428
2429        ia_css_rmgr_uninit();
2430
2431#if !defined(ISP2401)
2432        /* needed for reprogramming the inputformatter after power cycle of css */
2433        ifmtr_set_if_blocking_mode_reset = true;
2434#endif
2435
2436        if (!fw_explicitly_loaded)
2437                ia_css_unload_firmware();
2438
2439        ia_css_spctrl_unload_fw(SP0_ID);
2440        sh_css_sp_set_sp_running(false);
2441        /* check and free any remaining mipi frames */
2442        free_mipi_frames(NULL);
2443
2444        sh_css_sp_reset_global_vars();
2445
2446        ia_css_isys_uninit();
2447
2448        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_uninit() leave: return_void\n");
2449}
2450
2451int ia_css_irq_translate(
2452    unsigned int *irq_infos)
2453{
2454        enum virq_id    irq;
2455        enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_more_irqs;
2456        unsigned int infos = 0;
2457
2458        /* irq_infos can be NULL, but that would make the function useless */
2459        /* assert(irq_infos != NULL); */
2460        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2461                            "ia_css_irq_translate() enter: irq_infos=%p\n", irq_infos);
2462
2463        while (status == hrt_isp_css_irq_status_more_irqs) {
2464                status = virq_get_channel_id(&irq);
2465                if (status == hrt_isp_css_irq_status_error)
2466                        return -EINVAL;
2467
2468#if WITH_PC_MONITORING
2469                sh_css_print("PC_MONITORING: %s() irq = %d, sh_binary_running set to 0\n",
2470                             __func__, irq);
2471                sh_binary_running = 0;
2472#endif
2473
2474                switch (irq) {
2475                case virq_sp:
2476                        /* When SP goes to idle, info is available in the
2477                         * event queue. */
2478                        infos |= IA_CSS_IRQ_INFO_EVENTS_READY;
2479                        break;
2480                case virq_isp:
2481                        break;
2482                case virq_isys_sof:
2483                        infos |= IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF;
2484                        break;
2485                case virq_isys_eof:
2486                        infos |= IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF;
2487                        break;
2488                case virq_isys_csi:
2489                        infos |= IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR;
2490                        break;
2491#if !defined(ISP2401)
2492                case virq_ifmt0_id:
2493                        infos |= IA_CSS_IRQ_INFO_IF_ERROR;
2494                        break;
2495#endif
2496                case virq_dma:
2497                        infos |= IA_CSS_IRQ_INFO_DMA_ERROR;
2498                        break;
2499                case virq_sw_pin_0:
2500                        infos |= sh_css_get_sw_interrupt_value(0);
2501                        break;
2502                case virq_sw_pin_1:
2503                        infos |= sh_css_get_sw_interrupt_value(1);
2504                        /* pqiao TODO: also assumption here */
2505                        break;
2506                default:
2507                        break;
2508                }
2509        }
2510
2511        if (irq_infos)
2512                *irq_infos = infos;
2513
2514        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2515                            "ia_css_irq_translate() leave: irq_infos=%u\n",
2516                            infos);
2517
2518        return 0;
2519}
2520
2521int ia_css_irq_enable(
2522    enum ia_css_irq_info info,
2523    bool enable)
2524{
2525        enum virq_id    irq = N_virq_id;
2526
2527        IA_CSS_ENTER("info=%d, enable=%d", info, enable);
2528
2529        switch (info) {
2530#if !defined(ISP2401)
2531        case IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF:
2532                irq = virq_isys_sof;
2533                break;
2534        case IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF:
2535                irq = virq_isys_eof;
2536                break;
2537        case IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR:
2538                irq = virq_isys_csi;
2539                break;
2540        case IA_CSS_IRQ_INFO_IF_ERROR:
2541                irq = virq_ifmt0_id;
2542                break;
2543#else
2544        case IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF:
2545        case IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF:
2546        case IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR:
2547        case IA_CSS_IRQ_INFO_IF_ERROR:
2548                /* Just ignore those unused IRQs without printing errors */
2549                return 0;
2550#endif
2551        case IA_CSS_IRQ_INFO_DMA_ERROR:
2552                irq = virq_dma;
2553                break;
2554        case IA_CSS_IRQ_INFO_SW_0:
2555                irq = virq_sw_pin_0;
2556                break;
2557        case IA_CSS_IRQ_INFO_SW_1:
2558                irq = virq_sw_pin_1;
2559                break;
2560        default:
2561                IA_CSS_LEAVE_ERR(-EINVAL);
2562                return -EINVAL;
2563        }
2564
2565        cnd_virq_enable_channel(irq, enable);
2566
2567        IA_CSS_LEAVE_ERR(0);
2568        return 0;
2569}
2570
2571
2572static unsigned int
2573sh_css_get_sw_interrupt_value(unsigned int irq)
2574{
2575        unsigned int irq_value;
2576
2577        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2578                            "sh_css_get_sw_interrupt_value() enter: irq=%d\n", irq);
2579        irq_value = sh_css_sp_get_sw_interrupt_value(irq);
2580        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2581                            "sh_css_get_sw_interrupt_value() leave: irq_value=%d\n", irq_value);
2582        return irq_value;
2583}
2584
2585/* configure and load the copy binary, the next binary is used to
2586   determine whether the copy binary needs to do left padding. */
2587static int load_copy_binary(
2588    struct ia_css_pipe *pipe,
2589    struct ia_css_binary *copy_binary,
2590    struct ia_css_binary *next_binary)
2591{
2592        struct ia_css_frame_info copy_out_info, copy_in_info, copy_vf_info;
2593        unsigned int left_padding;
2594        int err;
2595        struct ia_css_binary_descr copy_descr;
2596
2597        /* next_binary can be NULL */
2598        assert(pipe);
2599        assert(copy_binary);
2600        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2601                            "load_copy_binary() enter:\n");
2602
2603        if (next_binary) {
2604                copy_out_info = next_binary->in_frame_info;
2605                left_padding = next_binary->left_padding;
2606        } else {
2607                copy_out_info = pipe->output_info[0];
2608                copy_vf_info = pipe->vf_output_info[0];
2609                ia_css_frame_info_set_format(&copy_vf_info, IA_CSS_FRAME_FORMAT_YUV_LINE);
2610                left_padding = 0;
2611        }
2612
2613        ia_css_pipe_get_copy_binarydesc(pipe, &copy_descr,
2614                                        &copy_in_info, &copy_out_info,
2615                                        (next_binary) ? NULL : NULL/*TODO: &copy_vf_info*/);
2616        err = ia_css_binary_find(&copy_descr, copy_binary);
2617        if (err)
2618                return err;
2619        copy_binary->left_padding = left_padding;
2620        return 0;
2621}
2622
2623static int
2624alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time)
2625{
2626        int err = 0;
2627        struct ia_css_frame_info ref_info;
2628        enum ia_css_pipe_id pipe_id;
2629        bool continuous;
2630        unsigned int i, idx;
2631        unsigned int num_frames;
2632
2633        IA_CSS_ENTER_PRIVATE("pipe = %p, init_time = %d", pipe, init_time);
2634
2635        if ((!pipe) || (!pipe->stream)) {
2636                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2637                return -EINVAL;
2638        }
2639
2640        pipe_id = pipe->mode;
2641        continuous = pipe->stream->config.continuous;
2642
2643        if (continuous) {
2644                if (init_time) {
2645                        num_frames = pipe->stream->config.init_num_cont_raw_buf;
2646                        pipe->stream->continuous_pipe = pipe;
2647                } else {
2648                        num_frames = pipe->stream->config.target_num_cont_raw_buf;
2649                }
2650        } else {
2651                num_frames = NUM_ONLINE_INIT_CONTINUOUS_FRAMES;
2652        }
2653
2654        if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
2655                ref_info = pipe->pipe_settings.preview.preview_binary.in_frame_info;
2656        } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) {
2657                ref_info = pipe->pipe_settings.video.video_binary.in_frame_info;
2658        } else {
2659                /* should not happen */
2660                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2661                return -EINVAL;
2662        }
2663
2664#if defined(ISP2401)
2665        /* For CSI2+, the continuous frame will hold the full input frame */
2666        ref_info.res.width = pipe->stream->config.input_config.input_res.width;
2667        ref_info.res.height = pipe->stream->config.input_config.input_res.height;
2668
2669        /* Ensure padded width is aligned for 2401 */
2670        ref_info.padded_width = CEIL_MUL(ref_info.res.width, 2 * ISP_VEC_NELEMS);
2671#endif
2672
2673#if !defined(HAS_NO_PACKED_RAW_PIXELS)
2674        if (pipe->stream->config.pack_raw_pixels) {
2675                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2676                                    "alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW_PACKED\n");
2677                ref_info.format = IA_CSS_FRAME_FORMAT_RAW_PACKED;
2678        } else
2679#endif
2680        {
2681                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2682                                    "alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW\n");
2683                ref_info.format = IA_CSS_FRAME_FORMAT_RAW;
2684        }
2685
2686        /* Write format back to binary */
2687        if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
2688                pipe->pipe_settings.preview.preview_binary.in_frame_info.format =
2689                    ref_info.format;
2690        } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) {
2691                pipe->pipe_settings.video.video_binary.in_frame_info.format = ref_info.format;
2692        } else {
2693                /* should not happen */
2694                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2695                return -EINVAL;
2696        }
2697
2698        if (init_time)
2699                idx = 0;
2700        else
2701                idx = pipe->stream->config.init_num_cont_raw_buf;
2702
2703        for (i = idx; i < NUM_CONTINUOUS_FRAMES; i++) {
2704                /* free previous frame */
2705                if (pipe->continuous_frames[i]) {
2706                        ia_css_frame_free(pipe->continuous_frames[i]);
2707                        pipe->continuous_frames[i] = NULL;
2708                }
2709                /* free previous metadata buffer */
2710                ia_css_metadata_free(pipe->cont_md_buffers[i]);
2711                pipe->cont_md_buffers[i] = NULL;
2712
2713                /* check if new frame needed */
2714                if (i < num_frames) {
2715                        /* allocate new frame */
2716                        err = ia_css_frame_allocate_from_info(
2717                                  &pipe->continuous_frames[i],
2718                                  &ref_info);
2719                        if (err) {
2720                                IA_CSS_LEAVE_ERR_PRIVATE(err);
2721                                return err;
2722                        }
2723                        /* allocate metadata buffer */
2724                        pipe->cont_md_buffers[i] = ia_css_metadata_allocate(
2725                                                       &pipe->stream->info.metadata_info);
2726                }
2727        }
2728        IA_CSS_LEAVE_ERR_PRIVATE(0);
2729        return 0;
2730}
2731
2732int
2733ia_css_alloc_continuous_frame_remain(struct ia_css_stream *stream)
2734{
2735        if (!stream)
2736                return -EINVAL;
2737        return alloc_continuous_frames(stream->continuous_pipe, false);
2738}
2739
2740static int
2741load_preview_binaries(struct ia_css_pipe *pipe)
2742{
2743        struct ia_css_frame_info prev_in_info,
2744                prev_bds_out_info,
2745                prev_out_info,
2746                prev_vf_info;
2747        struct ia_css_binary_descr preview_descr;
2748        bool online;
2749        int err = 0;
2750        bool need_vf_pp = false;
2751        bool need_isp_copy_binary = false;
2752#ifdef ISP2401
2753        bool sensor = false;
2754#else
2755        bool continuous;
2756#endif
2757        /* preview only have 1 output pin now */
2758        struct ia_css_frame_info *pipe_out_info = &pipe->output_info[0];
2759        struct ia_css_preview_settings *mycs  = &pipe->pipe_settings.preview;
2760
2761        IA_CSS_ENTER_PRIVATE("");
2762        assert(pipe);
2763        assert(pipe->stream);
2764        assert(pipe->mode == IA_CSS_PIPE_ID_PREVIEW);
2765
2766        online = pipe->stream->config.online;
2767#ifdef ISP2401
2768        sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
2769#else
2770        continuous = pipe->stream->config.continuous;
2771#endif
2772
2773        if (mycs->preview_binary.info)
2774                return 0;
2775
2776        err = ia_css_util_check_input(&pipe->stream->config, false, false);
2777        if (err)
2778                return err;
2779        err = ia_css_frame_check_info(pipe_out_info);
2780        if (err)
2781                return err;
2782
2783        /* Note: the current selection of vf_pp binary and
2784         * parameterization of the preview binary contains a few pieces
2785         * of hardcoded knowledge. This needs to be cleaned up such that
2786         * the binary selection becomes more generic.
2787         * The vf_pp binary is needed if one or more of the following features
2788         * are required:
2789         * 1. YUV downscaling.
2790         * 2. Digital zoom.
2791         * 3. An output format that is not supported by the preview binary.
2792         *    In practice this means something other than yuv_line or nv12.
2793         * The decision if the vf_pp binary is needed for YUV downscaling is
2794         * made after the preview binary selection, since some preview binaries
2795         * can perform the requested YUV downscaling.
2796         * */
2797        need_vf_pp = pipe->config.enable_dz;
2798        need_vf_pp |= pipe_out_info->format != IA_CSS_FRAME_FORMAT_YUV_LINE &&
2799        !(pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12 ||
2800          pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12_16 ||
2801          pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12_TILEY);
2802
2803        /* Preview step 1 */
2804        if (pipe->vf_yuv_ds_input_info.res.width)
2805                prev_vf_info = pipe->vf_yuv_ds_input_info;
2806        else
2807                prev_vf_info = *pipe_out_info;
2808        /* If vf_pp is needed, then preview must output yuv_line.
2809         * The exception is when vf_pp is manually disabled, that is only
2810         * used in combination with a pipeline extension that requires
2811         * yuv_line as input.
2812         * */
2813        if (need_vf_pp)
2814                ia_css_frame_info_set_format(&prev_vf_info,
2815                                             IA_CSS_FRAME_FORMAT_YUV_LINE);
2816
2817        err = ia_css_pipe_get_preview_binarydesc(
2818            pipe,
2819            &preview_descr,
2820            &prev_in_info,
2821            &prev_bds_out_info,
2822            &prev_out_info,
2823            &prev_vf_info);
2824        if (err)
2825                return err;
2826        err = ia_css_binary_find(&preview_descr, &mycs->preview_binary);
2827        if (err)
2828                return err;
2829
2830        if (IS_ISP2401) {
2831                /* The delay latency determines the number of invalid frames after
2832                * a stream is started. */
2833                pipe->num_invalid_frames = pipe->dvs_frame_delay;
2834                pipe->info.num_invalid_frames = pipe->num_invalid_frames;
2835
2836                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2837                                    "load_preview_binaries() num_invalid_frames=%d dvs_frame_delay=%d\n",
2838                                    pipe->num_invalid_frames, pipe->dvs_frame_delay);
2839        }
2840
2841        /* The vf_pp binary is needed when (further) YUV downscaling is required */
2842        need_vf_pp |= mycs->preview_binary.out_frame_info[0].res.width != pipe_out_info->res.width;
2843        need_vf_pp |= mycs->preview_binary.out_frame_info[0].res.height != pipe_out_info->res.height;
2844
2845        /* When vf_pp is needed, then the output format of the selected
2846         * preview binary must be yuv_line. If this is not the case,
2847         * then the preview binary selection is done again.
2848         */
2849        if (need_vf_pp &&
2850            (mycs->preview_binary.out_frame_info[0].format != IA_CSS_FRAME_FORMAT_YUV_LINE)) {
2851                /* Preview step 2 */
2852                if (pipe->vf_yuv_ds_input_info.res.width)
2853                        prev_vf_info = pipe->vf_yuv_ds_input_info;
2854                else
2855                        prev_vf_info = *pipe_out_info;
2856
2857                ia_css_frame_info_set_format(&prev_vf_info,
2858                                             IA_CSS_FRAME_FORMAT_YUV_LINE);
2859
2860                err = ia_css_pipe_get_preview_binarydesc(
2861                    pipe,
2862                    &preview_descr,
2863                    &prev_in_info,
2864                    &prev_bds_out_info,
2865                    &prev_out_info,
2866                    &prev_vf_info);
2867                if (err)
2868                        return err;
2869                err = ia_css_binary_find(&preview_descr,
2870                                         &mycs->preview_binary);
2871                if (err)
2872                        return err;
2873        }
2874
2875        if (need_vf_pp) {
2876                struct ia_css_binary_descr vf_pp_descr;
2877
2878                /* Viewfinder post-processing */
2879                ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
2880                                                &mycs->preview_binary.out_frame_info[0],
2881                                                pipe_out_info);
2882                err = ia_css_binary_find(&vf_pp_descr,
2883                                         &mycs->vf_pp_binary);
2884                if (err)
2885                        return err;
2886        }
2887
2888#ifdef ISP2401
2889        /* When the input system is 2401, only the Direct Sensor Mode
2890         * Offline Preview uses the ISP copy binary.
2891         */
2892        need_isp_copy_binary = !online && sensor;
2893#else
2894        /* About pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY:
2895         * This is typical the case with SkyCam (which has no input system) but it also applies to all cases
2896         * where the driver chooses for memory based input frames. In these cases, a copy binary (which typical
2897         * copies sensor data to DDR) does not have much use.
2898         */
2899        if (!IS_ISP2401)
2900                need_isp_copy_binary = !online && !continuous;
2901        else
2902                need_isp_copy_binary = !online && !continuous && !(pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY);
2903#endif
2904
2905        /* Copy */
2906        if (need_isp_copy_binary) {
2907                err = load_copy_binary(pipe,
2908                                       &mycs->copy_binary,
2909                                       &mycs->preview_binary);
2910                if (err)
2911                        return err;
2912        }
2913
2914        if (pipe->shading_table) {
2915                ia_css_shading_table_free(pipe->shading_table);
2916                pipe->shading_table = NULL;
2917        }
2918
2919        return 0;
2920}
2921
2922static void
2923ia_css_binary_unload(struct ia_css_binary *binary)
2924{
2925        ia_css_binary_destroy_isp_parameters(binary);
2926}
2927
2928static int
2929unload_preview_binaries(struct ia_css_pipe *pipe)
2930{
2931        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
2932
2933        if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
2934                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2935                return -EINVAL;
2936        }
2937        ia_css_binary_unload(&pipe->pipe_settings.preview.copy_binary);
2938        ia_css_binary_unload(&pipe->pipe_settings.preview.preview_binary);
2939        ia_css_binary_unload(&pipe->pipe_settings.preview.vf_pp_binary);
2940
2941        IA_CSS_LEAVE_ERR_PRIVATE(0);
2942        return 0;
2943}
2944
2945static const struct ia_css_fw_info *last_output_firmware(
2946    const struct ia_css_fw_info *fw)
2947{
2948        const struct ia_css_fw_info *last_fw = NULL;
2949        /* fw can be NULL */
2950        IA_CSS_ENTER_LEAVE_PRIVATE("");
2951
2952        for (; fw; fw = fw->next) {
2953                const struct ia_css_fw_info *info = fw;
2954
2955                if (info->info.isp.sp.enable.output)
2956                        last_fw = fw;
2957        }
2958        return last_fw;
2959}
2960
2961static int add_firmwares(
2962    struct ia_css_pipeline *me,
2963    struct ia_css_binary *binary,
2964    const struct ia_css_fw_info *fw,
2965    const struct ia_css_fw_info *last_fw,
2966    unsigned int binary_mode,
2967    struct ia_css_frame *in_frame,
2968    struct ia_css_frame *out_frame,
2969    struct ia_css_frame *vf_frame,
2970    struct ia_css_pipeline_stage **my_stage,
2971    struct ia_css_pipeline_stage **vf_stage)
2972{
2973        int err = 0;
2974        struct ia_css_pipeline_stage *extra_stage = NULL;
2975        struct ia_css_pipeline_stage_desc stage_desc;
2976
2977        /* all args can be NULL ??? */
2978        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2979                            "add_firmwares() enter:\n");
2980
2981        for (; fw; fw = fw->next) {
2982                struct ia_css_frame *out[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL};
2983                struct ia_css_frame *in = NULL;
2984                struct ia_css_frame *vf = NULL;
2985
2986                if ((fw == last_fw) && (fw->info.isp.sp.enable.out_frame  != 0))
2987                        out[0] = out_frame;
2988
2989                if (fw->info.isp.sp.enable.in_frame != 0)
2990                        in = in_frame;
2991
2992                if (fw->info.isp.sp.enable.out_frame != 0)
2993                        vf = vf_frame;
2994
2995                ia_css_pipe_get_firmwares_stage_desc(&stage_desc, binary,
2996                                                     out, in, vf, fw, binary_mode);
2997                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
2998                                                           &extra_stage);
2999                if (err)
3000                        return err;
3001                if (fw->info.isp.sp.enable.output != 0)
3002                        in_frame = extra_stage->args.out_frame[0];
3003                if (my_stage && !*my_stage && extra_stage)
3004                        *my_stage = extra_stage;
3005                if (vf_stage && !*vf_stage && extra_stage &&
3006                    fw->info.isp.sp.enable.vf_veceven)
3007                        *vf_stage = extra_stage;
3008        }
3009        return err;
3010}
3011
3012static int add_vf_pp_stage(
3013    struct ia_css_pipe *pipe,
3014    struct ia_css_frame *in_frame,
3015    struct ia_css_frame *out_frame,
3016    struct ia_css_binary *vf_pp_binary,
3017    struct ia_css_pipeline_stage **vf_pp_stage)
3018{
3019        struct ia_css_pipeline *me = NULL;
3020        const struct ia_css_fw_info *last_fw = NULL;
3021        int err = 0;
3022        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3023        struct ia_css_pipeline_stage_desc stage_desc;
3024
3025        /* out_frame can be NULL ??? */
3026
3027        if (!pipe)
3028                return -EINVAL;
3029        if (!in_frame)
3030                return -EINVAL;
3031        if (!vf_pp_binary)
3032                return -EINVAL;
3033        if (!vf_pp_stage)
3034                return -EINVAL;
3035
3036        ia_css_pipe_util_create_output_frames(out_frames);
3037        me = &pipe->pipeline;
3038
3039        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3040                            "add_vf_pp_stage() enter:\n");
3041
3042        *vf_pp_stage = NULL;
3043
3044        last_fw = last_output_firmware(pipe->vf_stage);
3045        if (!pipe->extra_config.disable_vf_pp) {
3046                if (last_fw) {
3047                        ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3048                        ia_css_pipe_get_generic_stage_desc(&stage_desc, vf_pp_binary,
3049                                                           out_frames, in_frame, NULL);
3050                } else {
3051                        ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3052                        ia_css_pipe_get_generic_stage_desc(&stage_desc, vf_pp_binary,
3053                                                           out_frames, in_frame, NULL);
3054                }
3055                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, vf_pp_stage);
3056                if (err)
3057                        return err;
3058                in_frame = (*vf_pp_stage)->args.out_frame[0];
3059        }
3060        err = add_firmwares(me, vf_pp_binary, pipe->vf_stage, last_fw,
3061                            IA_CSS_BINARY_MODE_VF_PP,
3062                            in_frame, out_frame, NULL,
3063                            vf_pp_stage, NULL);
3064        return err;
3065}
3066
3067static int add_yuv_scaler_stage(
3068    struct ia_css_pipe *pipe,
3069    struct ia_css_pipeline *me,
3070    struct ia_css_frame *in_frame,
3071    struct ia_css_frame *out_frame,
3072    struct ia_css_frame *internal_out_frame,
3073    struct ia_css_binary *yuv_scaler_binary,
3074    struct ia_css_pipeline_stage **pre_vf_pp_stage)
3075{
3076        const struct ia_css_fw_info *last_fw;
3077        int err = 0;
3078        struct ia_css_frame *vf_frame = NULL;
3079        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3080        struct ia_css_pipeline_stage_desc stage_desc;
3081
3082        /* out_frame can be NULL ??? */
3083        assert(in_frame);
3084        assert(pipe);
3085        assert(me);
3086        assert(yuv_scaler_binary);
3087        assert(pre_vf_pp_stage);
3088        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3089                            "add_yuv_scaler_stage() enter:\n");
3090
3091        *pre_vf_pp_stage = NULL;
3092        ia_css_pipe_util_create_output_frames(out_frames);
3093
3094        last_fw = last_output_firmware(pipe->output_stage);
3095
3096        if (last_fw) {
3097                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3098                ia_css_pipe_get_generic_stage_desc(&stage_desc,
3099                                                   yuv_scaler_binary, out_frames, in_frame, vf_frame);
3100        } else {
3101                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3102                ia_css_pipe_util_set_output_frames(out_frames, 1, internal_out_frame);
3103                ia_css_pipe_get_generic_stage_desc(&stage_desc,
3104                                                   yuv_scaler_binary, out_frames, in_frame, vf_frame);
3105        }
3106        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3107                                                   pre_vf_pp_stage);
3108        if (err)
3109                return err;
3110        in_frame = (*pre_vf_pp_stage)->args.out_frame[0];
3111
3112        err = add_firmwares(me, yuv_scaler_binary, pipe->output_stage, last_fw,
3113                            IA_CSS_BINARY_MODE_CAPTURE_PP,
3114                            in_frame, out_frame, vf_frame,
3115                            NULL, pre_vf_pp_stage);
3116        /* If a firmware produce vf_pp output, we set that as vf_pp input */
3117        (*pre_vf_pp_stage)->args.vf_downscale_log2 =
3118            yuv_scaler_binary->vf_downscale_log2;
3119
3120        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3121                            "add_yuv_scaler_stage() leave:\n");
3122        return err;
3123}
3124
3125static int add_capture_pp_stage(
3126    struct ia_css_pipe *pipe,
3127    struct ia_css_pipeline *me,
3128    struct ia_css_frame *in_frame,
3129    struct ia_css_frame *out_frame,
3130    struct ia_css_binary *capture_pp_binary,
3131    struct ia_css_pipeline_stage **capture_pp_stage)
3132{
3133        const struct ia_css_fw_info *last_fw = NULL;
3134        int err = 0;
3135        struct ia_css_frame *vf_frame = NULL;
3136        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3137        struct ia_css_pipeline_stage_desc stage_desc;
3138
3139        /* out_frame can be NULL ??? */
3140        assert(in_frame);
3141        assert(pipe);
3142        assert(me);
3143        assert(capture_pp_binary);
3144        assert(capture_pp_stage);
3145        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3146                            "add_capture_pp_stage() enter:\n");
3147
3148        *capture_pp_stage = NULL;
3149        ia_css_pipe_util_create_output_frames(out_frames);
3150
3151        last_fw = last_output_firmware(pipe->output_stage);
3152        err = ia_css_frame_allocate_from_info(&vf_frame,
3153                                              &capture_pp_binary->vf_frame_info);
3154        if (err)
3155                return err;
3156        if (last_fw)    {
3157                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3158                ia_css_pipe_get_generic_stage_desc(&stage_desc,
3159                                                   capture_pp_binary, out_frames, NULL, vf_frame);
3160        } else {
3161                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3162                ia_css_pipe_get_generic_stage_desc(&stage_desc,
3163                                                   capture_pp_binary, out_frames, NULL, vf_frame);
3164        }
3165        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3166                                                   capture_pp_stage);
3167        if (err)
3168                return err;
3169        err = add_firmwares(me, capture_pp_binary, pipe->output_stage, last_fw,
3170                            IA_CSS_BINARY_MODE_CAPTURE_PP,
3171                            in_frame, out_frame, vf_frame,
3172                            NULL, capture_pp_stage);
3173        /* If a firmware produce vf_pp output, we set that as vf_pp input */
3174        if (*capture_pp_stage) {
3175                (*capture_pp_stage)->args.vf_downscale_log2 =
3176                    capture_pp_binary->vf_downscale_log2;
3177        }
3178        return err;
3179}
3180
3181static void sh_css_setup_queues(void)
3182{
3183        const struct ia_css_fw_info *fw;
3184        unsigned int HIVE_ADDR_host_sp_queues_initialized;
3185
3186        sh_css_hmm_buffer_record_init();
3187
3188        sh_css_event_init_irq_mask();
3189
3190        fw = &sh_css_sp_fw;
3191        HIVE_ADDR_host_sp_queues_initialized =
3192            fw->info.sp.host_sp_queues_initialized;
3193
3194        ia_css_bufq_init();
3195
3196        /* set "host_sp_queues_initialized" to "true" */
3197        sp_dmem_store_uint32(SP0_ID,
3198                             (unsigned int)sp_address_of(host_sp_queues_initialized),
3199                             (uint32_t)(1));
3200        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "sh_css_setup_queues() leave:\n");
3201}
3202
3203static int
3204init_vf_frameinfo_defaults(struct ia_css_pipe *pipe,
3205                           struct ia_css_frame *vf_frame, unsigned int idx)
3206{
3207        int err = 0;
3208        unsigned int thread_id;
3209        enum sh_css_queue_id queue_id;
3210
3211        assert(vf_frame);
3212
3213        sh_css_pipe_get_viewfinder_frame_info(pipe, &vf_frame->info, idx);
3214        vf_frame->contiguous = false;
3215        vf_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3216        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3217        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, thread_id, &queue_id);
3218        vf_frame->dynamic_queue_id = queue_id;
3219        vf_frame->buf_type = IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx;
3220
3221        err = ia_css_frame_init_planes(vf_frame);
3222        return err;
3223}
3224
3225#ifdef ISP2401
3226static unsigned int
3227get_crop_lines_for_bayer_order(
3228    const struct ia_css_stream_config *config)
3229{
3230        assert(config);
3231        if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR)
3232            || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
3233                return 1;
3234
3235        return 0;
3236}
3237
3238static unsigned int
3239get_crop_columns_for_bayer_order(
3240    const struct ia_css_stream_config *config)
3241{
3242        assert(config);
3243        if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB)
3244            || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
3245                return 1;
3246
3247        return 0;
3248}
3249
3250/* This function is to get the sum of all extra pixels in addition to the effective
3251 * input, it includes dvs envelop and filter run-in */
3252static void get_pipe_extra_pixel(struct ia_css_pipe *pipe,
3253                                 unsigned int *extra_row, unsigned int *extra_column)
3254{
3255        enum ia_css_pipe_id pipe_id = pipe->mode;
3256        unsigned int left_cropping = 0, top_cropping = 0;
3257        unsigned int i;
3258        struct ia_css_resolution dvs_env = pipe->config.dvs_envelope;
3259
3260        /* The dvs envelope info may not be correctly sent down via pipe config
3261         * The check is made and the correct value is populated in the binary info
3262         * Use this value when computing crop, else excess lines may get trimmed
3263         */
3264        switch (pipe_id) {
3265        case IA_CSS_PIPE_ID_PREVIEW:
3266                if (pipe->pipe_settings.preview.preview_binary.info) {
3267                        left_cropping =
3268                            pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.left_cropping;
3269                        top_cropping =
3270                            pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.top_cropping;
3271                }
3272                dvs_env = pipe->pipe_settings.preview.preview_binary.dvs_envelope;
3273                break;
3274        case IA_CSS_PIPE_ID_VIDEO:
3275                if (pipe->pipe_settings.video.video_binary.info) {
3276                        left_cropping =
3277                            pipe->pipe_settings.video.video_binary.info->sp.pipeline.left_cropping;
3278                        top_cropping =
3279                            pipe->pipe_settings.video.video_binary.info->sp.pipeline.top_cropping;
3280                }
3281                dvs_env = pipe->pipe_settings.video.video_binary.dvs_envelope;
3282                break;
3283        case IA_CSS_PIPE_ID_CAPTURE:
3284                for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
3285                        if (pipe->pipe_settings.capture.primary_binary[i].info) {
3286                                left_cropping +=
3287                                    pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.left_cropping;
3288                                top_cropping +=
3289                                    pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.top_cropping;
3290                        }
3291                        dvs_env.width +=
3292                            pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.width;
3293                        dvs_env.height +=
3294                            pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.height;
3295                }
3296                break;
3297        default:
3298                break;
3299        }
3300
3301        *extra_row = top_cropping + dvs_env.height;
3302        *extra_column = left_cropping + dvs_env.width;
3303}
3304
3305void
3306ia_css_get_crop_offsets(
3307    struct ia_css_pipe *pipe,
3308    struct ia_css_frame_info *in_frame)
3309{
3310        unsigned int row = 0;
3311        unsigned int column = 0;
3312        struct ia_css_resolution *input_res;
3313        struct ia_css_resolution *effective_res;
3314        unsigned int extra_row = 0, extra_col = 0;
3315        unsigned int min_reqd_height, min_reqd_width;
3316
3317        assert(pipe);
3318        assert(pipe->stream);
3319        assert(in_frame);
3320
3321        IA_CSS_ENTER_PRIVATE("pipe = %p effective_wd = %u effective_ht = %u",
3322                             pipe, pipe->config.input_effective_res.width,
3323                             pipe->config.input_effective_res.height);
3324
3325        input_res = &pipe->stream->config.input_config.input_res;
3326#ifndef ISP2401
3327        effective_res = &pipe->stream->config.input_config.effective_res;
3328#else
3329        effective_res = &pipe->config.input_effective_res;
3330#endif
3331
3332        get_pipe_extra_pixel(pipe, &extra_row, &extra_col);
3333
3334        in_frame->raw_bayer_order = pipe->stream->config.input_config.bayer_order;
3335
3336        min_reqd_height = effective_res->height + extra_row;
3337        min_reqd_width = effective_res->width + extra_col;
3338
3339        if (input_res->height > min_reqd_height) {
3340                row = (input_res->height - min_reqd_height) / 2;
3341                row &= ~0x1;
3342        }
3343        if (input_res->width > min_reqd_width) {
3344                column = (input_res->width - min_reqd_width) / 2;
3345                column &= ~0x1;
3346        }
3347
3348        /*
3349         * TODO:
3350         * 1. Require the special support for RAW10 packed mode.
3351         * 2. Require the special support for the online use cases.
3352         */
3353
3354        /* ISP expects GRBG bayer order, we skip one line and/or one row
3355         * to correct in case the input bayer order is different.
3356         */
3357        column += get_crop_columns_for_bayer_order(&pipe->stream->config);
3358        row += get_crop_lines_for_bayer_order(&pipe->stream->config);
3359
3360        in_frame->crop_info.start_column = column;
3361        in_frame->crop_info.start_line = row;
3362
3363        IA_CSS_LEAVE_PRIVATE("void start_col: %u start_row: %u", column, row);
3364
3365        return;
3366}
3367#endif
3368
3369static int
3370init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
3371                                  struct ia_css_frame *frame, enum ia_css_frame_format format)
3372{
3373        struct ia_css_frame *in_frame;
3374        int err = 0;
3375        unsigned int thread_id;
3376        enum sh_css_queue_id queue_id;
3377
3378        assert(frame);
3379        in_frame = frame;
3380
3381        in_frame->info.format = format;
3382
3383#ifdef ISP2401
3384        if (format == IA_CSS_FRAME_FORMAT_RAW)
3385                in_frame->info.format = (pipe->stream->config.pack_raw_pixels) ?
3386                IA_CSS_FRAME_FORMAT_RAW_PACKED : IA_CSS_FRAME_FORMAT_RAW;
3387#endif
3388
3389        in_frame->info.res.width = pipe->stream->config.input_config.input_res.width;
3390        in_frame->info.res.height = pipe->stream->config.input_config.input_res.height;
3391        in_frame->info.raw_bit_depth =
3392        ia_css_pipe_util_pipe_input_format_bpp(pipe);
3393        ia_css_frame_info_set_width(&in_frame->info, pipe->stream->config.input_config.input_res.width, 0);
3394        in_frame->contiguous = false;
3395        in_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3396        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3397        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id);
3398        in_frame->dynamic_queue_id = queue_id;
3399        in_frame->buf_type = IA_CSS_BUFFER_TYPE_INPUT_FRAME;
3400#ifdef ISP2401
3401        ia_css_get_crop_offsets(pipe, &in_frame->info);
3402#endif
3403        err = ia_css_frame_init_planes(in_frame);
3404
3405        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3406                            "init_in_frameinfo_memory_defaults() bayer_order = %d:\n", in_frame->info.raw_bayer_order);
3407
3408        return err;
3409}
3410
3411static int
3412init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
3413                            struct ia_css_frame *out_frame, unsigned int idx)
3414{
3415        int err = 0;
3416        unsigned int thread_id;
3417        enum sh_css_queue_id queue_id;
3418
3419        assert(out_frame);
3420
3421        sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, idx);
3422        out_frame->contiguous = false;
3423        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3424        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3425        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, thread_id, &queue_id);
3426        out_frame->dynamic_queue_id = queue_id;
3427        out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx;
3428        err = ia_css_frame_init_planes(out_frame);
3429
3430        return err;
3431}
3432
3433/* Create stages for video pipe */
3434static int create_host_video_pipeline(struct ia_css_pipe *pipe)
3435{
3436        struct ia_css_pipeline_stage_desc stage_desc;
3437        struct ia_css_binary *copy_binary, *video_binary,
3438                       *yuv_scaler_binary, *vf_pp_binary;
3439        struct ia_css_pipeline_stage *copy_stage  = NULL;
3440        struct ia_css_pipeline_stage *video_stage = NULL;
3441        struct ia_css_pipeline_stage *yuv_scaler_stage  = NULL;
3442        struct ia_css_pipeline_stage *vf_pp_stage = NULL;
3443        struct ia_css_pipeline *me;
3444        struct ia_css_frame *in_frame = NULL;
3445        struct ia_css_frame *out_frame;
3446        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3447        struct ia_css_frame *vf_frame = NULL;
3448        int err = 0;
3449        bool need_copy   = false;
3450        bool need_vf_pp  = false;
3451        bool need_yuv_pp = false;
3452        bool need_in_frameinfo_memory = false;
3453
3454        unsigned int i, num_yuv_scaler;
3455        bool *is_output_stage = NULL;
3456
3457        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3458        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
3459                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3460                return -EINVAL;
3461        }
3462        ia_css_pipe_util_create_output_frames(out_frames);
3463        out_frame = &pipe->out_frame_struct;
3464
3465        /* pipeline already created as part of create_host_pipeline_structure */
3466        me = &pipe->pipeline;
3467        ia_css_pipeline_clean(me);
3468
3469        me->dvs_frame_delay = pipe->dvs_frame_delay;
3470
3471#ifdef ISP2401
3472        /* When the input system is 2401, always enable 'in_frameinfo_memory'
3473         * except for the following: online or continuous
3474         */
3475        need_in_frameinfo_memory = !(pipe->stream->config.online ||
3476                                     pipe->stream->config.continuous);
3477#else
3478        /* Construct in_frame info (only in case we have dynamic input */
3479        need_in_frameinfo_memory = pipe->stream->config.mode ==
3480                                   IA_CSS_INPUT_MODE_MEMORY;
3481#endif
3482
3483        /* Construct in_frame info (only in case we have dynamic input */
3484        if (need_in_frameinfo_memory) {
3485                in_frame = &pipe->in_frame_struct;
3486                err = init_in_frameinfo_memory_defaults(pipe, in_frame,
3487                                                        IA_CSS_FRAME_FORMAT_RAW);
3488                if (err)
3489                        goto ERR;
3490        }
3491
3492        out_frame->data = 0;
3493        err = init_out_frameinfo_defaults(pipe, out_frame, 0);
3494        if (err)
3495                goto ERR;
3496
3497        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
3498                vf_frame = &pipe->vf_frame_struct;
3499                vf_frame->data = 0;
3500                err = init_vf_frameinfo_defaults(pipe, vf_frame, 0);
3501                if (err)
3502                        goto ERR;
3503        }
3504
3505        copy_binary  = &pipe->pipe_settings.video.copy_binary;
3506        video_binary = &pipe->pipe_settings.video.video_binary;
3507        vf_pp_binary = &pipe->pipe_settings.video.vf_pp_binary;
3508
3509        yuv_scaler_binary = pipe->pipe_settings.video.yuv_scaler_binary;
3510        num_yuv_scaler  = pipe->pipe_settings.video.num_yuv_scaler;
3511        is_output_stage = pipe->pipe_settings.video.is_output_stage;
3512
3513        need_copy   = (copy_binary && copy_binary->info);
3514        need_vf_pp  = (vf_pp_binary && vf_pp_binary->info);
3515        need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
3516
3517        if (need_copy) {
3518                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3519                ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
3520                                                   out_frames, NULL, NULL);
3521                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3522                                                           &copy_stage);
3523                if (err)
3524                        goto ERR;
3525                in_frame = me->stages->args.out_frame[0];
3526        } else if (pipe->stream->config.continuous) {
3527#ifdef ISP2401
3528                /* When continuous is enabled, configure in_frame with the
3529                 * last pipe, which is the copy pipe.
3530                 */
3531                in_frame = pipe->stream->last_pipe->continuous_frames[0];
3532#else
3533                in_frame = pipe->continuous_frames[0];
3534#endif
3535        }
3536
3537        ia_css_pipe_util_set_output_frames(out_frames, 0,
3538                                           need_yuv_pp ? NULL : out_frame);
3539
3540        /* when the video binary supports a second output pin,
3541           it can directly produce the vf_frame.  */
3542        if (need_vf_pp) {
3543                ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
3544                                                   out_frames, in_frame, NULL);
3545        } else {
3546                ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
3547                                                   out_frames, in_frame, vf_frame);
3548        }
3549        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3550                                                   &video_stage);
3551        if (err)
3552                goto ERR;
3553
3554        /* If we use copy iso video, the input must be yuv iso raw */
3555        if (video_stage) {
3556                video_stage->args.copy_vf =
3557                    video_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
3558                video_stage->args.copy_output = video_stage->args.copy_vf;
3559        }
3560
3561        /* when the video binary supports only 1 output pin, vf_pp is needed to
3562        produce the vf_frame.*/
3563        if (need_vf_pp && video_stage) {
3564                in_frame = video_stage->args.out_vf_frame;
3565                err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
3566                                      &vf_pp_stage);
3567                if (err)
3568                        goto ERR;
3569        }
3570        if (video_stage) {
3571                int frm;
3572
3573                for (frm = 0; frm < NUM_TNR_FRAMES; frm++) {
3574                        video_stage->args.tnr_frames[frm] =
3575                            pipe->pipe_settings.video.tnr_frames[frm];
3576                }
3577                for (frm = 0; frm < MAX_NUM_VIDEO_DELAY_FRAMES; frm++) {
3578                        video_stage->args.delay_frames[frm] =
3579                            pipe->pipe_settings.video.delay_frames[frm];
3580                }
3581        }
3582
3583        /* Append Extension on Video out, if enabled */
3584        if (!need_vf_pp && video_stage && pipe->config.acc_extension &&
3585            (pipe->config.acc_extension->info.isp.type == IA_CSS_ACC_OUTPUT)) {
3586                struct ia_css_frame *out = NULL;
3587                struct ia_css_frame *in = NULL;
3588
3589                if ((pipe->config.acc_extension->info.isp.sp.enable.output) &&
3590                    (pipe->config.acc_extension->info.isp.sp.enable.in_frame) &&
3591                    (pipe->config.acc_extension->info.isp.sp.enable.out_frame)) {
3592                        /* In/Out Frame mapping to support output frame extension.*/
3593                        out = video_stage->args.out_frame[0];
3594                        err = ia_css_frame_allocate_from_info(&in, &pipe->output_info[0]);
3595                        if (err)
3596                                goto ERR;
3597                        video_stage->args.out_frame[0] = in;
3598                }
3599
3600                err = add_firmwares(me, video_binary, pipe->output_stage,
3601                                    last_output_firmware(pipe->output_stage),
3602                                    IA_CSS_BINARY_MODE_VIDEO,
3603                                    in, out, NULL, &video_stage, NULL);
3604                if (err)
3605                        goto ERR;
3606        }
3607
3608        if (need_yuv_pp && video_stage) {
3609                struct ia_css_frame *tmp_in_frame = video_stage->args.out_frame[0];
3610                struct ia_css_frame *tmp_out_frame = NULL;
3611
3612                for (i = 0; i < num_yuv_scaler; i++) {
3613                        tmp_out_frame = is_output_stage[i] ? out_frame : NULL;
3614
3615                        err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
3616                                                   tmp_out_frame, NULL,
3617                                                   &yuv_scaler_binary[i],
3618                                                   &yuv_scaler_stage);
3619
3620                        if (err) {
3621                                IA_CSS_LEAVE_ERR_PRIVATE(err);
3622                                return err;
3623                        }
3624                        /* we use output port 1 as internal output port */
3625                        if (yuv_scaler_stage)
3626                                tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
3627                }
3628        }
3629
3630        pipe->pipeline.acquire_isp_each_stage = false;
3631        ia_css_pipeline_finalize_stages(&pipe->pipeline,
3632                                        pipe->stream->config.continuous);
3633
3634ERR:
3635        IA_CSS_LEAVE_ERR_PRIVATE(err);
3636        return err;
3637}
3638
3639static int
3640create_host_acc_pipeline(struct ia_css_pipe *pipe)
3641{
3642        int err = 0;
3643        const struct ia_css_fw_info *fw;
3644        unsigned int i;
3645
3646        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3647        if ((!pipe) || (!pipe->stream)) {
3648                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3649                return -EINVAL;
3650        }
3651
3652        pipe->pipeline.num_execs = pipe->config.acc_num_execs;
3653        /* Reset pipe_qos_config to default disable all QOS extension stages */
3654        if (pipe->config.acc_extension)
3655                pipe->pipeline.pipe_qos_config = 0;
3656
3657        fw = pipe->vf_stage;
3658        for (i = 0; fw; fw = fw->next) {
3659                err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
3660                if (err)
3661                        goto ERR;
3662        }
3663
3664        for (i = 0; i < pipe->config.num_acc_stages; i++) {
3665                struct ia_css_fw_info *fw = pipe->config.acc_stages[i];
3666
3667                err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
3668                if (err)
3669                        goto ERR;
3670        }
3671
3672        ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
3673
3674ERR:
3675        IA_CSS_LEAVE_ERR_PRIVATE(err);
3676        return err;
3677}
3678
3679/* Create stages for preview */
3680static int
3681create_host_preview_pipeline(struct ia_css_pipe *pipe)
3682{
3683        struct ia_css_pipeline_stage *copy_stage = NULL;
3684        struct ia_css_pipeline_stage *preview_stage = NULL;
3685        struct ia_css_pipeline_stage *vf_pp_stage = NULL;
3686        struct ia_css_pipeline_stage_desc stage_desc;
3687        struct ia_css_pipeline *me = NULL;
3688        struct ia_css_binary *copy_binary, *preview_binary, *vf_pp_binary = NULL;
3689        struct ia_css_frame *in_frame = NULL;
3690        int err = 0;
3691        struct ia_css_frame *out_frame;
3692        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3693        bool need_in_frameinfo_memory = false;
3694#ifdef ISP2401
3695        bool sensor = false;
3696        bool buffered_sensor = false;
3697        bool online = false;
3698        bool continuous = false;
3699#endif
3700
3701        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3702        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
3703                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3704                return -EINVAL;
3705        }
3706
3707        ia_css_pipe_util_create_output_frames(out_frames);
3708        /* pipeline already created as part of create_host_pipeline_structure */
3709        me = &pipe->pipeline;
3710        ia_css_pipeline_clean(me);
3711
3712#ifdef ISP2401
3713        /* When the input system is 2401, always enable 'in_frameinfo_memory'
3714         * except for the following:
3715         * - Direct Sensor Mode Online Preview
3716         * - Buffered Sensor Mode Online Preview
3717         * - Direct Sensor Mode Continuous Preview
3718         * - Buffered Sensor Mode Continuous Preview
3719         */
3720        sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
3721        buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
3722        online = pipe->stream->config.online;
3723        continuous = pipe->stream->config.continuous;
3724        need_in_frameinfo_memory =
3725        !((sensor && (online || continuous)) || (buffered_sensor && (online || continuous)));
3726#else
3727        /* Construct in_frame info (only in case we have dynamic input */
3728        need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
3729#endif
3730        if (need_in_frameinfo_memory) {
3731                err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
3732                                                        IA_CSS_FRAME_FORMAT_RAW);
3733                if (err)
3734                        goto ERR;
3735
3736                in_frame = &me->in_frame;
3737        } else {
3738                in_frame = NULL;
3739        }
3740
3741        err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
3742        if (err)
3743                goto ERR;
3744        out_frame = &me->out_frame[0];
3745
3746        copy_binary    = &pipe->pipe_settings.preview.copy_binary;
3747        preview_binary = &pipe->pipe_settings.preview.preview_binary;
3748        if (pipe->pipe_settings.preview.vf_pp_binary.info)
3749                vf_pp_binary = &pipe->pipe_settings.preview.vf_pp_binary;
3750
3751        if (pipe->pipe_settings.preview.copy_binary.info) {
3752                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3753                ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
3754                                                   out_frames, NULL, NULL);
3755                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3756                                                           &copy_stage);
3757                if (err)
3758                        goto ERR;
3759                in_frame = me->stages->args.out_frame[0];
3760        } else if (pipe->stream->config.continuous) {
3761#ifdef ISP2401
3762                /* When continuous is enabled, configure in_frame with the
3763                 * last pipe, which is the copy pipe.
3764                 */
3765                if (continuous || !online)
3766                        in_frame = pipe->stream->last_pipe->continuous_frames[0];
3767
3768#else
3769                in_frame = pipe->continuous_frames[0];
3770#endif
3771        }
3772
3773        if (vf_pp_binary) {
3774                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3775                ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
3776                                                   out_frames, in_frame, NULL);
3777        } else {
3778                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3779                ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
3780                                                   out_frames, in_frame, NULL);
3781        }
3782        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3783                                                   &preview_stage);
3784        if (err)
3785                goto ERR;
3786        /* If we use copy iso preview, the input must be yuv iso raw */
3787        preview_stage->args.copy_vf =
3788            preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
3789        preview_stage->args.copy_output = !preview_stage->args.copy_vf;
3790        if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) {
3791                /* in case of copy, use the vf frame as output frame */
3792                preview_stage->args.out_vf_frame =
3793                    preview_stage->args.out_frame[0];
3794        }
3795        if (vf_pp_binary) {
3796                if (preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)
3797                        in_frame = preview_stage->args.out_vf_frame;
3798                else
3799                        in_frame = preview_stage->args.out_frame[0];
3800                err = add_vf_pp_stage(pipe, in_frame, out_frame, vf_pp_binary,
3801                                      &vf_pp_stage);
3802                if (err)
3803                        goto ERR;
3804        }
3805
3806        pipe->pipeline.acquire_isp_each_stage = false;
3807        ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
3808
3809ERR:
3810        IA_CSS_LEAVE_ERR_PRIVATE(err);
3811        return err;
3812}
3813
3814static void send_raw_frames(struct ia_css_pipe *pipe)
3815{
3816        if (pipe->stream->config.continuous) {
3817                unsigned int i;
3818
3819                sh_css_update_host2sp_cont_num_raw_frames
3820                (pipe->stream->config.init_num_cont_raw_buf, true);
3821                sh_css_update_host2sp_cont_num_raw_frames
3822                (pipe->stream->config.target_num_cont_raw_buf, false);
3823
3824                /* Hand-over all the SP-internal buffers */
3825                for (i = 0; i < pipe->stream->config.init_num_cont_raw_buf; i++) {
3826                        sh_css_update_host2sp_offline_frame(i,
3827                                                            pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
3828                }
3829        }
3830
3831        return;
3832}
3833
3834static int
3835preview_start(struct ia_css_pipe *pipe)
3836{
3837        int err = 0;
3838        struct ia_css_pipe *copy_pipe, *capture_pipe;
3839        struct ia_css_pipe *acc_pipe;
3840        enum sh_css_pipe_config_override copy_ovrd;
3841        enum ia_css_input_mode preview_pipe_input_mode;
3842        const struct ia_css_coordinate *coord = NULL;
3843        const struct ia_css_isp_parameters *params = NULL;
3844
3845        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3846        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
3847                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3848                return -EINVAL;
3849        }
3850
3851        preview_pipe_input_mode = pipe->stream->config.mode;
3852
3853        copy_pipe    = pipe->pipe_settings.preview.copy_pipe;
3854        capture_pipe = pipe->pipe_settings.preview.capture_pipe;
3855        acc_pipe     = pipe->pipe_settings.preview.acc_pipe;
3856
3857        sh_css_metrics_start_frame();
3858
3859        /* multi stream video needs mipi buffers */
3860        err = send_mipi_frames(pipe);
3861        if (err) {
3862                IA_CSS_LEAVE_ERR_PRIVATE(err);
3863                return err;
3864        }
3865        send_raw_frames(pipe);
3866
3867        {
3868                unsigned int thread_id;
3869
3870                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3871                copy_ovrd = 1 << thread_id;
3872
3873                if (pipe->stream->cont_capt) {
3874                        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
3875                                                         &thread_id);
3876                        copy_ovrd |= 1 << thread_id;
3877                }
3878        }
3879
3880        if (IS_ISP2401) {
3881                coord = &pipe->config.internal_frame_origin_bqs_on_sctbl;
3882                params = pipe->stream->isp_params_configs;
3883        }
3884
3885        /* Construct and load the copy pipe */
3886        if (pipe->stream->config.continuous) {
3887                sh_css_sp_init_pipeline(&copy_pipe->pipeline,
3888                                        IA_CSS_PIPE_ID_COPY,
3889                                        (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
3890                                        false,
3891                                        pipe->stream->config.pixels_per_clock == 2, false,
3892                                        false, pipe->required_bds_factor,
3893                                        copy_ovrd,
3894                                        pipe->stream->config.mode,
3895                                        &pipe->stream->config.metadata_config,
3896                                        &pipe->stream->info.metadata_info,
3897                                        pipe->stream->config.source.port.port,
3898                                        coord,
3899                                        params);
3900
3901                /* make the preview pipe start with mem mode input, copy handles
3902                   the actual mode */
3903                preview_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY;
3904        }
3905
3906        /* Construct and load the capture pipe */
3907        if (pipe->stream->cont_capt) {
3908                sh_css_sp_init_pipeline(&capture_pipe->pipeline,
3909                                        IA_CSS_PIPE_ID_CAPTURE,
3910                                        (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
3911                                        capture_pipe->config.default_capture_config.enable_xnr != 0,
3912                                        capture_pipe->stream->config.pixels_per_clock == 2,
3913                                        true, /* continuous */
3914                                        false, /* offline */
3915                                        capture_pipe->required_bds_factor,
3916                                        0,
3917                                        IA_CSS_INPUT_MODE_MEMORY,
3918                                        &pipe->stream->config.metadata_config,
3919                                        &pipe->stream->info.metadata_info,
3920                                        (enum mipi_port_id)0,
3921                                        coord,
3922                                        params);
3923        }
3924
3925        if (acc_pipe) {
3926                sh_css_sp_init_pipeline(&acc_pipe->pipeline,
3927                                        IA_CSS_PIPE_ID_ACC,
3928                                        (uint8_t)ia_css_pipe_get_pipe_num(acc_pipe),
3929                                        false,
3930                                        pipe->stream->config.pixels_per_clock == 2,
3931                                        false, /* continuous */
3932                                        false, /* offline */
3933                                        pipe->required_bds_factor,
3934                                        0,
3935                                        IA_CSS_INPUT_MODE_MEMORY,
3936                                        NULL,
3937                                        NULL,
3938                                        (enum mipi_port_id)0,
3939                                        coord,
3940                                        params);
3941        }
3942
3943        start_pipe(pipe, copy_ovrd, preview_pipe_input_mode);
3944
3945        IA_CSS_LEAVE_ERR_PRIVATE(err);
3946        return err;
3947}
3948
3949int
3950ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
3951                           const struct ia_css_buffer *buffer)
3952{
3953        int return_err = 0;
3954        unsigned int thread_id;
3955        enum sh_css_queue_id queue_id;
3956        struct ia_css_pipeline *pipeline;
3957        struct ia_css_pipeline_stage *stage;
3958        struct ia_css_rmgr_vbuf_handle p_vbuf;
3959        struct ia_css_rmgr_vbuf_handle *h_vbuf;
3960        struct sh_css_hmm_buffer ddr_buffer;
3961        enum ia_css_buffer_type buf_type;
3962        enum ia_css_pipe_id pipe_id;
3963        bool ret_err;
3964
3965        IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
3966
3967        if ((!pipe) || (!buffer)) {
3968                IA_CSS_LEAVE_ERR(-EINVAL);
3969                return -EINVAL;
3970        }
3971
3972        buf_type = buffer->type;
3973        /* following code will be enabled when IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
3974           is removed */
3975#if 0
3976        if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
3977                bool found_pipe = false;
3978
3979                for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
3980                        if ((buffer->data.frame->info.res.width == pipe->output_info[i].res.width) &&
3981                            (buffer->data.frame->info.res.height == pipe->output_info[i].res.height)) {
3982                                buf_type += i;
3983                                found_pipe = true;
3984                                break;
3985                        }
3986                }
3987                if (!found_pipe)
3988                        return -EINVAL;
3989        }
3990        if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
3991                bool found_pipe = false;
3992
3993                for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
3994                        if ((buffer->data.frame->info.res.width == pipe->vf_output_info[i].res.width) &&
3995                            (buffer->data.frame->info.res.height == pipe->vf_output_info[i].res.height)) {
3996                                buf_type += i;
3997                                found_pipe = true;
3998                                break;
3999                        }
4000                }
4001                if (!found_pipe)
4002                        return -EINVAL;
4003        }
4004#endif
4005        pipe_id = pipe->mode;
4006
4007        IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type);
4008
4009        assert(pipe_id < IA_CSS_PIPE_ID_NUM);
4010        assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
4011        if (buf_type == IA_CSS_BUFFER_TYPE_INVALID ||
4012            buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE ||
4013            pipe_id >= IA_CSS_PIPE_ID_NUM) {
4014                IA_CSS_LEAVE_ERR(-EINVAL);
4015                return -EINVAL;
4016        }
4017
4018        ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4019        if (!ret_err) {
4020                IA_CSS_LEAVE_ERR(-EINVAL);
4021                return -EINVAL;
4022        }
4023
4024        ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
4025        if (!ret_err) {
4026                IA_CSS_LEAVE_ERR(-EINVAL);
4027                return -EINVAL;
4028        }
4029
4030        if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
4031                IA_CSS_LEAVE_ERR(-EINVAL);
4032                return -EINVAL;
4033        }
4034
4035        if (!sh_css_sp_is_running()) {
4036                IA_CSS_LOG("SP is not running!");
4037                IA_CSS_LEAVE_ERR(-EBUSY);
4038                /* SP is not running. The queues are not valid */
4039                return -EBUSY;
4040        }
4041
4042        pipeline = &pipe->pipeline;
4043
4044        assert(pipeline ||
4045               pipe_id == IA_CSS_PIPE_ID_COPY ||
4046               pipe_id == IA_CSS_PIPE_ID_ACC);
4047
4048        assert(sizeof(NULL) <= sizeof(ddr_buffer.kernel_ptr));
4049        ddr_buffer.kernel_ptr = HOST_ADDRESS(NULL);
4050        ddr_buffer.cookie_ptr = buffer->driver_cookie;
4051        ddr_buffer.timing_data = buffer->timing_data;
4052
4053        if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) {
4054                if (!buffer->data.stats_3a) {
4055                        IA_CSS_LEAVE_ERR(-EINVAL);
4056                        return -EINVAL;
4057                }
4058                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_3a);
4059                ddr_buffer.payload.s3a = *buffer->data.stats_3a;
4060        } else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) {
4061                if (!buffer->data.stats_dvs) {
4062                        IA_CSS_LEAVE_ERR(-EINVAL);
4063                        return -EINVAL;
4064                }
4065                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_dvs);
4066                ddr_buffer.payload.dis = *buffer->data.stats_dvs;
4067        } else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
4068                if (!buffer->data.metadata) {
4069                        IA_CSS_LEAVE_ERR(-EINVAL);
4070                        return -EINVAL;
4071                }
4072                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.metadata);
4073                ddr_buffer.payload.metadata = *buffer->data.metadata;
4074        } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
4075                   buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
4076                   buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
4077                   buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
4078                   buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) {
4079                if (!buffer->data.frame) {
4080                        IA_CSS_LEAVE_ERR(-EINVAL);
4081                        return -EINVAL;
4082                }
4083                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.frame);
4084                ddr_buffer.payload.frame.frame_data = buffer->data.frame->data;
4085                ddr_buffer.payload.frame.flashed = 0;
4086
4087                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4088                                    "ia_css_pipe_enqueue_buffer() buf_type=%d, data(DDR address)=0x%x\n",
4089                                    buf_type, buffer->data.frame->data);
4090
4091#if CONFIG_ON_FRAME_ENQUEUE()
4092                return_err = set_config_on_frame_enqueue(
4093                                 &buffer->data.frame->info,
4094                                 &ddr_buffer.payload.frame);
4095                if (return_err) {
4096                        IA_CSS_LEAVE_ERR(return_err);
4097                        return return_err;
4098                }
4099#endif
4100        }
4101
4102        /* start of test for using rmgr for acq/rel memory */
4103        p_vbuf.vptr = 0;
4104        p_vbuf.count = 0;
4105        p_vbuf.size = sizeof(struct sh_css_hmm_buffer);
4106        h_vbuf = &p_vbuf;
4107        /* TODO: change next to correct pool for optimization */
4108        ia_css_rmgr_acq_vbuf(hmm_buffer_pool, &h_vbuf);
4109
4110        if ((!h_vbuf) || (h_vbuf->vptr == 0x0)) {
4111                IA_CSS_LEAVE_ERR(-EINVAL);
4112                return -EINVAL;
4113        }
4114
4115        hmm_store(h_vbuf->vptr,
4116                  (void *)(&ddr_buffer),
4117                  sizeof(struct sh_css_hmm_buffer));
4118        if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS ||
4119            buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS ||
4120            buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS) {
4121                if (!pipeline) {
4122                        ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
4123                        IA_CSS_LOG("pipeline is empty!");
4124                        IA_CSS_LEAVE_ERR(-EINVAL);
4125                        return -EINVAL;
4126                }
4127
4128                for (stage = pipeline->stages; stage; stage = stage->next) {
4129                        /* The SP will read the params
4130                                after it got empty 3a and dis */
4131                        if (STATS_ENABLED(stage)) {
4132                                /* there is a stage that needs it */
4133                                return_err = ia_css_bufq_enqueue_buffer(thread_id,
4134                                                                        queue_id,
4135                                                                        (uint32_t)h_vbuf->vptr);
4136                        }
4137                }
4138        } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
4139                   buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
4140                   buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
4141                   buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
4142                   buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME ||
4143                   buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
4144                return_err = ia_css_bufq_enqueue_buffer(thread_id,
4145                                                        queue_id,
4146                                                        (uint32_t)h_vbuf->vptr);
4147#if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS)
4148                if (!return_err &&
4149                    buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
4150                        IA_CSS_LOG("pfp: enqueued OF %d to q %d thread %d",
4151                                   ddr_buffer.payload.frame.frame_data,
4152                                   queue_id, thread_id);
4153                }
4154#endif
4155        }
4156
4157        if (!return_err) {
4158                if (sh_css_hmm_buffer_record_acquire(
4159                        h_vbuf, buf_type,
4160                        HOST_ADDRESS(ddr_buffer.kernel_ptr))) {
4161                        IA_CSS_LOG("send vbuf=%p", h_vbuf);
4162                } else {
4163                        return_err = -EINVAL;
4164                        IA_CSS_ERROR("hmm_buffer_record[]: no available slots\n");
4165                }
4166        }
4167
4168        /*
4169         * Tell the SP which queues are not empty,
4170         * by sending the software event.
4171         */
4172        if (!return_err) {
4173                if (!sh_css_sp_is_running()) {
4174                        /* SP is not running. The queues are not valid */
4175                        IA_CSS_LOG("SP is not running!");
4176                        IA_CSS_LEAVE_ERR(-EBUSY);
4177                        return -EBUSY;
4178                }
4179                return_err = ia_css_bufq_enqueue_psys_event(
4180                                 IA_CSS_PSYS_SW_EVENT_BUFFER_ENQUEUED,
4181                                 (uint8_t)thread_id,
4182                                 queue_id,
4183                                 0);
4184        } else {
4185                ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
4186                IA_CSS_ERROR("buffer not enqueued");
4187        }
4188
4189        IA_CSS_LEAVE("return value = %d", return_err);
4190
4191        return return_err;
4192}
4193
4194/*
4195 * TODO: Free up the hmm memory space.
4196         */
4197int
4198ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
4199                           struct ia_css_buffer *buffer)
4200{
4201        int return_err;
4202        enum sh_css_queue_id queue_id;
4203        ia_css_ptr ddr_buffer_addr = (ia_css_ptr)0;
4204        struct sh_css_hmm_buffer ddr_buffer;
4205        enum ia_css_buffer_type buf_type;
4206        enum ia_css_pipe_id pipe_id;
4207        unsigned int thread_id;
4208        hrt_address kernel_ptr = 0;
4209        bool ret_err;
4210
4211        IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
4212
4213        if ((!pipe) || (!buffer)) {
4214                IA_CSS_LEAVE_ERR(-EINVAL);
4215                return -EINVAL;
4216        }
4217
4218        pipe_id = pipe->mode;
4219
4220        buf_type = buffer->type;
4221
4222        IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type);
4223
4224        ddr_buffer.kernel_ptr = 0;
4225
4226        ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4227        if (!ret_err) {
4228                IA_CSS_LEAVE_ERR(-EINVAL);
4229                return -EINVAL;
4230        }
4231
4232        ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
4233        if (!ret_err) {
4234                IA_CSS_LEAVE_ERR(-EINVAL);
4235                return -EINVAL;
4236        }
4237
4238        if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
4239                IA_CSS_LEAVE_ERR(-EINVAL);
4240                return -EINVAL;
4241        }
4242
4243        if (!sh_css_sp_is_running()) {
4244                IA_CSS_LOG("SP is not running!");
4245                IA_CSS_LEAVE_ERR(-EBUSY);
4246                /* SP is not running. The queues are not valid */
4247                return -EBUSY;
4248        }
4249
4250        return_err = ia_css_bufq_dequeue_buffer(queue_id,
4251                                                (uint32_t *)&ddr_buffer_addr);
4252
4253        if (!return_err) {
4254                struct ia_css_frame *frame;
4255                struct sh_css_hmm_buffer_record *hmm_buffer_record = NULL;
4256
4257                IA_CSS_LOG("receive vbuf=%x", (int)ddr_buffer_addr);
4258
4259                /* Validate the ddr_buffer_addr and buf_type */
4260                hmm_buffer_record = sh_css_hmm_buffer_record_validate(
4261                    ddr_buffer_addr, buf_type);
4262                if (hmm_buffer_record) {
4263                        /* valid hmm_buffer_record found. Save the kernel_ptr
4264                         * for validation after performing hmm_load.  The
4265                         * vbuf handle and buffer_record can be released.
4266                         */
4267                        kernel_ptr = hmm_buffer_record->kernel_ptr;
4268                        ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &hmm_buffer_record->h_vbuf);
4269                        sh_css_hmm_buffer_record_reset(hmm_buffer_record);
4270                } else {
4271                        IA_CSS_ERROR("hmm_buffer_record not found (0x%x) buf_type(%d)",
4272                                     ddr_buffer_addr, buf_type);
4273                        IA_CSS_LEAVE_ERR(-EINVAL);
4274                        return -EINVAL;
4275                }
4276
4277                hmm_load(ddr_buffer_addr,
4278                         &ddr_buffer,
4279                         sizeof(struct sh_css_hmm_buffer));
4280
4281                /* if the kernel_ptr is 0 or an invalid, return an error.
4282                 * do not access the buffer via the kernal_ptr.
4283                 */
4284                if ((ddr_buffer.kernel_ptr == 0) ||
4285                    (kernel_ptr != HOST_ADDRESS(ddr_buffer.kernel_ptr))) {
4286                        IA_CSS_ERROR("kernel_ptr invalid");
4287                        IA_CSS_ERROR("expected: (0x%llx)", (u64)kernel_ptr);
4288                        IA_CSS_ERROR("actual: (0x%llx)", (u64)HOST_ADDRESS(ddr_buffer.kernel_ptr));
4289                        IA_CSS_ERROR("buf_type: %d\n", buf_type);
4290                        IA_CSS_LEAVE_ERR(-EINVAL);
4291                        return -EINVAL;
4292                }
4293
4294                if (ddr_buffer.kernel_ptr != 0) {
4295                        /* buffer->exp_id : all instances to be removed later once the driver change
4296                         * is completed. See patch #5758 for reference */
4297                        buffer->exp_id = 0;
4298                        buffer->driver_cookie = ddr_buffer.cookie_ptr;
4299                        buffer->timing_data = ddr_buffer.timing_data;
4300
4301                        if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
4302                            buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
4303                                buffer->isys_eof_clock_tick.ticks = ddr_buffer.isys_eof_clock_tick;
4304                        }
4305
4306                        switch (buf_type) {
4307                        case IA_CSS_BUFFER_TYPE_INPUT_FRAME:
4308                        case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
4309                        case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
4310                                if (pipe && pipe->stop_requested) {
4311#if !defined(ISP2401)
4312                                        /* free mipi frames only for old input system
4313                                         * for 2401 it is done in ia_css_stream_destroy call
4314                                         */
4315                                        return_err = free_mipi_frames(pipe);
4316                                        if (return_err) {
4317                                                IA_CSS_LOG("free_mipi_frames() failed");
4318                                                IA_CSS_LEAVE_ERR(return_err);
4319                                                return return_err;
4320                                        }
4321#endif
4322                                        pipe->stop_requested = false;
4323                                }
4324                                fallthrough;
4325                        case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
4326                        case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
4327                                frame = (struct ia_css_frame *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4328                                buffer->data.frame = frame;
4329                                buffer->exp_id = ddr_buffer.payload.frame.exp_id;
4330                                frame->exp_id = ddr_buffer.payload.frame.exp_id;
4331                                frame->isp_config_id = ddr_buffer.payload.frame.isp_parameters_id;
4332                                if (ddr_buffer.payload.frame.flashed == 1)
4333                                        frame->flash_state =
4334                                            IA_CSS_FRAME_FLASH_STATE_PARTIAL;
4335                                if (ddr_buffer.payload.frame.flashed == 2)
4336                                        frame->flash_state =
4337                                            IA_CSS_FRAME_FLASH_STATE_FULL;
4338                                frame->valid = pipe->num_invalid_frames == 0;
4339                                if (!frame->valid)
4340                                        pipe->num_invalid_frames--;
4341
4342                                if (frame->info.format == IA_CSS_FRAME_FORMAT_BINARY_8) {
4343#ifdef ISP2401
4344                                        frame->planes.binary.size = frame->data_bytes;
4345#else
4346                                        frame->planes.binary.size =
4347                                            sh_css_sp_get_binary_copy_size();
4348#endif
4349                                }
4350#if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS)
4351                                if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
4352                                        IA_CSS_LOG("pfp: dequeued OF %d with config id %d thread %d",
4353                                                   frame->data, frame->isp_config_id, thread_id);
4354                                }
4355#endif
4356
4357                                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4358                                                    "ia_css_pipe_dequeue_buffer() buf_type=%d, data(DDR address)=0x%x\n",
4359                                                    buf_type, buffer->data.frame->data);
4360
4361                                break;
4362                        case IA_CSS_BUFFER_TYPE_3A_STATISTICS:
4363                                buffer->data.stats_3a =
4364                                    (struct ia_css_isp_3a_statistics *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4365                                buffer->exp_id = ddr_buffer.payload.s3a.exp_id;
4366                                buffer->data.stats_3a->exp_id = ddr_buffer.payload.s3a.exp_id;
4367                                buffer->data.stats_3a->isp_config_id = ddr_buffer.payload.s3a.isp_config_id;
4368                                break;
4369                        case IA_CSS_BUFFER_TYPE_DIS_STATISTICS:
4370                                buffer->data.stats_dvs =
4371                                    (struct ia_css_isp_dvs_statistics *)
4372                                    HOST_ADDRESS(ddr_buffer.kernel_ptr);
4373                                buffer->exp_id = ddr_buffer.payload.dis.exp_id;
4374                                buffer->data.stats_dvs->exp_id = ddr_buffer.payload.dis.exp_id;
4375                                break;
4376                        case IA_CSS_BUFFER_TYPE_LACE_STATISTICS:
4377                                break;
4378                        case IA_CSS_BUFFER_TYPE_METADATA:
4379                                buffer->data.metadata =
4380                                    (struct ia_css_metadata *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4381                                buffer->exp_id = ddr_buffer.payload.metadata.exp_id;
4382                                buffer->data.metadata->exp_id = ddr_buffer.payload.metadata.exp_id;
4383                                break;
4384                        default:
4385                                return_err = -EINVAL;
4386                                break;
4387                        }
4388                }
4389        }
4390
4391        /*
4392         * Tell the SP which queues are not full,
4393         * by sending the software event.
4394         */
4395        if (!return_err) {
4396                if (!sh_css_sp_is_running()) {
4397                        IA_CSS_LOG("SP is not running!");
4398                        IA_CSS_LEAVE_ERR(-EBUSY);
4399                        /* SP is not running. The queues are not valid */
4400                        return -EBUSY;
4401                }
4402                ia_css_bufq_enqueue_psys_event(
4403                    IA_CSS_PSYS_SW_EVENT_BUFFER_DEQUEUED,
4404                    0,
4405                    queue_id,
4406                    0);
4407        }
4408        IA_CSS_LEAVE("buffer=%p", buffer);
4409
4410        return return_err;
4411}
4412
4413/*
4414 * Cannot Move this to event module as it is of ia_css_event_type which is declared in ia_css.h
4415 * TODO: modify and move it if possible.
4416 *
4417 * !!!IMPORTANT!!! KEEP THE FOLLOWING IN SYNC:
4418 * 1) "enum ia_css_event_type"                                  (ia_css_event_public.h)
4419 * 2) "enum sh_css_sp_event_type"                               (sh_css_internal.h)
4420 * 3) "enum ia_css_event_type event_id_2_event_mask"            (event_handler.sp.c)
4421 * 4) "enum ia_css_event_type convert_event_sp_to_host_domain"  (sh_css.c)
4422 */
4423static enum ia_css_event_type convert_event_sp_to_host_domain[] = {
4424        IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE,    /** Output frame ready. */
4425        IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE,     /** Second output frame ready. */
4426        IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE, /** Viewfinder Output frame ready. */
4427        IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE,  /** Second viewfinder Output frame ready. */
4428        IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE,   /** Indication that 3A statistics are available. */
4429        IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE,  /** Indication that DIS statistics are available. */
4430        IA_CSS_EVENT_TYPE_PIPELINE_DONE,        /** Pipeline Done event, sent after last pipeline stage. */
4431        IA_CSS_EVENT_TYPE_FRAME_TAGGED,         /** Frame tagged. */
4432        IA_CSS_EVENT_TYPE_INPUT_FRAME_DONE,     /** Input frame ready. */
4433        IA_CSS_EVENT_TYPE_METADATA_DONE,        /** Metadata ready. */
4434        IA_CSS_EVENT_TYPE_LACE_STATISTICS_DONE, /** Indication that LACE statistics are available. */
4435        IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE,   /** Extension stage executed. */
4436        IA_CSS_EVENT_TYPE_TIMER,                /** Timing measurement data. */
4437        IA_CSS_EVENT_TYPE_PORT_EOF,             /** End Of Frame event, sent when in buffered sensor mode. */
4438        IA_CSS_EVENT_TYPE_FW_WARNING,           /** Performance warning encountered by FW */
4439        IA_CSS_EVENT_TYPE_FW_ASSERT,            /** Assertion hit by FW */
4440        0,                                      /* error if sp passes  SH_CSS_SP_EVENT_NR_OF_TYPES as a valid event. */
4441};
4442
4443int
4444ia_css_dequeue_event(struct ia_css_event *event)
4445{
4446        return ia_css_dequeue_psys_event(event);
4447}
4448
4449int
4450ia_css_dequeue_psys_event(struct ia_css_event *event)
4451{
4452        enum ia_css_pipe_id pipe_id = 0;
4453        u8 payload[4] = {0, 0, 0, 0};
4454        int ret_err;
4455
4456        /*TODO:
4457         * a) use generic decoding function , same as the one used by sp.
4458         * b) group decode and dequeue into eventQueue module
4459         *
4460         * We skip the IA_CSS_ENTER logging call
4461         * to avoid flooding the logs when the host application
4462         * uses polling. */
4463        if (!event)
4464                return -EINVAL;
4465
4466        /* SP is not running. The queues are not valid */
4467        if (!sh_css_sp_is_running())
4468                return -EBUSY;
4469
4470        /* dequeue the event (if any) from the psys event queue */
4471        ret_err = ia_css_bufq_dequeue_psys_event(payload);
4472        if (ret_err)
4473                return ret_err;
4474
4475        IA_CSS_LOG("event dequeued from psys event queue");
4476
4477        /* Tell the SP that we dequeued an event from the event queue. */
4478        ia_css_bufq_enqueue_psys_event(
4479            IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0);
4480
4481        /* Events are decoded into 4 bytes of payload, the first byte
4482         * contains the sp event type. This is converted to a host enum.
4483         * TODO: can this enum conversion be eliminated */
4484        event->type = convert_event_sp_to_host_domain[payload[0]];
4485        /* Some sane default values since not all events use all fields. */
4486        event->pipe = NULL;
4487        event->port = MIPI_PORT0_ID;
4488        event->exp_id = 0;
4489        event->fw_warning = IA_CSS_FW_WARNING_NONE;
4490        event->fw_handle = 0;
4491        event->timer_data = 0;
4492        event->timer_code = 0;
4493        event->timer_subcode = 0;
4494
4495        if (event->type == IA_CSS_EVENT_TYPE_TIMER) {
4496                /* timer event ??? get the 2nd event and decode the data into the event struct */
4497                u32 tmp_data;
4498                /* 1st event: LSB 16-bit timer data and code */
4499                event->timer_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8));
4500                event->timer_code = payload[2];
4501                payload[0] = payload[1] = payload[2] = payload[3] = 0;
4502                ret_err = ia_css_bufq_dequeue_psys_event(payload);
4503                if (ret_err) {
4504                        /* no 2nd event ??? an error */
4505                        /* Putting IA_CSS_ERROR is resulting in failures in
4506                         * Merrifield smoke testing  */
4507                        IA_CSS_WARNING("Timer: Error de-queuing the 2nd TIMER event!!!\n");
4508                        return ret_err;
4509                }
4510                ia_css_bufq_enqueue_psys_event(
4511                    IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0);
4512                event->type = convert_event_sp_to_host_domain[payload[0]];
4513                /* It's a timer */
4514                if (event->type == IA_CSS_EVENT_TYPE_TIMER) {
4515                        /* 2nd event data: MSB 16-bit timer and subcode */
4516                        tmp_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8));
4517                        event->timer_data |= (tmp_data << 16);
4518                        event->timer_subcode = payload[2];
4519                } else {
4520                /* It's a non timer event. So clear first half of the timer event data.
4521                * If the second part of the TIMER event is not received, we discard
4522                * the first half of the timer data and process the non timer event without
4523                * affecting the flow. So the non timer event falls through
4524                * the code. */
4525                        event->timer_data = 0;
4526                        event->timer_code = 0;
4527                        event->timer_subcode = 0;
4528                        IA_CSS_ERROR("Missing 2nd timer event. Timer event discarded");
4529                }
4530        }
4531        if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF) {
4532                event->port = (enum mipi_port_id)payload[1];
4533                event->exp_id = payload[3];
4534        } else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING) {
4535                event->fw_warning = (enum ia_css_fw_warning)payload[1];
4536                /* exp_id is only available in these warning types */
4537                if (event->fw_warning == IA_CSS_FW_WARNING_EXP_ID_LOCKED ||
4538                    event->fw_warning == IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED)
4539                        event->exp_id = payload[3];
4540        } else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT) {
4541                event->fw_assert_module_id = payload[1]; /* module */
4542                event->fw_assert_line_no = (payload[2] << 8) + payload[3];
4543                /* payload[2] is line_no>>8, payload[3] is line_no&0xff */
4544        } else if (event->type != IA_CSS_EVENT_TYPE_TIMER) {
4545                /* pipe related events.
4546                 * payload[1] contains the pipe_num,
4547                 * payload[2] contains the pipe_id. These are different. */
4548                event->pipe = find_pipe_by_num(payload[1]);
4549                pipe_id = (enum ia_css_pipe_id)payload[2];
4550                /* Check to see if pipe still exists */
4551                if (!event->pipe)
4552                        return -EBUSY;
4553
4554                if (event->type == IA_CSS_EVENT_TYPE_FRAME_TAGGED) {
4555                        /* find the capture pipe that goes with this */
4556                        int i, n;
4557
4558                        n = event->pipe->stream->num_pipes;
4559                        for (i = 0; i < n; i++) {
4560                                struct ia_css_pipe *p =
4561                                            event->pipe->stream->pipes[i];
4562                                if (p->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
4563                                        event->pipe = p;
4564                                        break;
4565                                }
4566                        }
4567                        event->exp_id = payload[3];
4568                }
4569                if (event->type == IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE) {
4570                        /* payload[3] contains the acc fw handle. */
4571                        u32 stage_num = (uint32_t)payload[3];
4572
4573                        ret_err = ia_css_pipeline_get_fw_from_stage(
4574                                      &event->pipe->pipeline,
4575                                      stage_num,
4576                                      &event->fw_handle);
4577                        if (ret_err) {
4578                                IA_CSS_ERROR("Invalid stage num received for ACC event. stage_num:%u",
4579                                             stage_num);
4580                                return ret_err;
4581                        }
4582                }
4583        }
4584
4585        if (event->pipe)
4586                IA_CSS_LEAVE("event_id=%d, pipe_id=%d", event->type, pipe_id);
4587        else
4588                IA_CSS_LEAVE("event_id=%d", event->type);
4589
4590        return 0;
4591}
4592
4593int
4594ia_css_dequeue_isys_event(struct ia_css_event *event)
4595{
4596        u8 payload[4] = {0, 0, 0, 0};
4597        int err = 0;
4598
4599        /* We skip the IA_CSS_ENTER logging call
4600         * to avoid flooding the logs when the host application
4601         * uses polling. */
4602        if (!event)
4603                return -EINVAL;
4604
4605        /* SP is not running. The queues are not valid */
4606        if (!sh_css_sp_is_running())
4607                return -EBUSY;
4608
4609        err = ia_css_bufq_dequeue_isys_event(payload);
4610        if (err)
4611                return err;
4612
4613        IA_CSS_LOG("event dequeued from isys event queue");
4614
4615        /* Update SP state to indicate that element was dequeued. */
4616        ia_css_bufq_enqueue_isys_event(IA_CSS_ISYS_SW_EVENT_EVENT_DEQUEUED);
4617
4618        /* Fill return struct with appropriate info */
4619        event->type = IA_CSS_EVENT_TYPE_PORT_EOF;
4620        /* EOF events are associated with a CSI port, not with a pipe */
4621        event->pipe = NULL;
4622        event->port = payload[1];
4623        event->exp_id = payload[3];
4624
4625        IA_CSS_LEAVE_ERR(err);
4626        return err;
4627}
4628
4629static void
4630acc_start(struct ia_css_pipe *pipe)
4631{
4632        assert(pipe);
4633        assert(pipe->stream);
4634
4635        start_pipe(pipe, SH_CSS_PIPE_CONFIG_OVRD_NO_OVRD,
4636                   pipe->stream->config.mode);
4637}
4638
4639static int
4640sh_css_pipe_start(struct ia_css_stream *stream)
4641{
4642        int err = 0;
4643
4644        struct ia_css_pipe *pipe;
4645        enum ia_css_pipe_id pipe_id;
4646        unsigned int thread_id;
4647
4648        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
4649
4650        if (!stream) {
4651                IA_CSS_LEAVE_ERR(-EINVAL);
4652                return -EINVAL;
4653        }
4654        pipe = stream->last_pipe;
4655        if (!pipe) {
4656                IA_CSS_LEAVE_ERR(-EINVAL);
4657                return -EINVAL;
4658        }
4659
4660        pipe_id = pipe->mode;
4661
4662        if (stream->started) {
4663                IA_CSS_WARNING("Cannot start stream that is already started");
4664                IA_CSS_LEAVE_ERR(err);
4665                return err;
4666        }
4667
4668        pipe->stop_requested = false;
4669
4670        switch (pipe_id) {
4671        case IA_CSS_PIPE_ID_PREVIEW:
4672                err = preview_start(pipe);
4673                break;
4674        case IA_CSS_PIPE_ID_VIDEO:
4675                err = video_start(pipe);
4676                break;
4677        case IA_CSS_PIPE_ID_CAPTURE:
4678                err = capture_start(pipe);
4679                break;
4680        case IA_CSS_PIPE_ID_YUVPP:
4681                err = yuvpp_start(pipe);
4682                break;
4683        case IA_CSS_PIPE_ID_ACC:
4684                acc_start(pipe);
4685                break;
4686        default:
4687                err = -EINVAL;
4688        }
4689        /* DH regular multi pipe - not continuous mode: start the next pipes too */
4690        if (!stream->config.continuous) {
4691                int i;
4692
4693                for (i = 1; i < stream->num_pipes && 0 == err ; i++) {
4694                        switch (stream->pipes[i]->mode) {
4695                        case IA_CSS_PIPE_ID_PREVIEW:
4696                                stream->pipes[i]->stop_requested = false;
4697                                err = preview_start(stream->pipes[i]);
4698                                break;
4699                        case IA_CSS_PIPE_ID_VIDEO:
4700                                stream->pipes[i]->stop_requested = false;
4701                                err = video_start(stream->pipes[i]);
4702                                break;
4703                        case IA_CSS_PIPE_ID_CAPTURE:
4704                                stream->pipes[i]->stop_requested = false;
4705                                err = capture_start(stream->pipes[i]);
4706                                break;
4707                        case IA_CSS_PIPE_ID_YUVPP:
4708                                stream->pipes[i]->stop_requested = false;
4709                                err = yuvpp_start(stream->pipes[i]);
4710                                break;
4711                        case IA_CSS_PIPE_ID_ACC:
4712                                stream->pipes[i]->stop_requested = false;
4713                                acc_start(stream->pipes[i]);
4714                                break;
4715                        default:
4716                                err = -EINVAL;
4717                        }
4718                }
4719        }
4720        if (err) {
4721                IA_CSS_LEAVE_ERR_PRIVATE(err);
4722                return err;
4723        }
4724
4725        /* Force ISP parameter calculation after a mode change
4726         * Acceleration API examples pass NULL for stream but they
4727         * don't use ISP parameters anyway. So this should be okay.
4728         * The SP binary (jpeg) copy does not use any parameters.
4729         */
4730        if (!copy_on_sp(pipe)) {
4731                sh_css_invalidate_params(stream);
4732                err = sh_css_param_update_isp_params(pipe,
4733                                                     stream->isp_params_configs, true, NULL);
4734                if (err) {
4735                        IA_CSS_LEAVE_ERR_PRIVATE(err);
4736                        return err;
4737                }
4738        }
4739
4740        ia_css_debug_pipe_graph_dump_epilogue();
4741
4742        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4743
4744        if (!sh_css_sp_is_running()) {
4745                IA_CSS_LEAVE_ERR_PRIVATE(-EBUSY);
4746                /* SP is not running. The queues are not valid */
4747                return -EBUSY;
4748        }
4749        ia_css_bufq_enqueue_psys_event(IA_CSS_PSYS_SW_EVENT_START_STREAM,
4750                                       (uint8_t)thread_id, 0, 0);
4751
4752        /* DH regular multi pipe - not continuous mode: enqueue event to the next pipes too */
4753        if (!stream->config.continuous) {
4754                int i;
4755
4756                for (i = 1; i < stream->num_pipes; i++) {
4757                        ia_css_pipeline_get_sp_thread_id(
4758                            ia_css_pipe_get_pipe_num(stream->pipes[i]),
4759                            &thread_id);
4760                        ia_css_bufq_enqueue_psys_event(
4761                            IA_CSS_PSYS_SW_EVENT_START_STREAM,
4762                            (uint8_t)thread_id, 0, 0);
4763                }
4764        }
4765
4766        /* in case of continuous capture mode, we also start capture thread and copy thread*/
4767        if (pipe->stream->config.continuous) {
4768                struct ia_css_pipe *copy_pipe = NULL;
4769
4770                if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4771                        copy_pipe = pipe->pipe_settings.preview.copy_pipe;
4772                else if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
4773                        copy_pipe = pipe->pipe_settings.video.copy_pipe;
4774
4775                if (!copy_pipe) {
4776                        IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4777                        return -EINVAL;
4778                }
4779                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(copy_pipe),
4780                                                 &thread_id);
4781                /* by the time we reach here q is initialized and handle is available.*/
4782                ia_css_bufq_enqueue_psys_event(
4783                    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4784                    (uint8_t)thread_id, 0,  0);
4785        }
4786        if (pipe->stream->cont_capt) {
4787                struct ia_css_pipe *capture_pipe = NULL;
4788
4789                if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4790                        capture_pipe = pipe->pipe_settings.preview.capture_pipe;
4791                else if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
4792                        capture_pipe = pipe->pipe_settings.video.capture_pipe;
4793
4794                if (!capture_pipe) {
4795                        IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4796                        return -EINVAL;
4797                }
4798                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
4799                                                 &thread_id);
4800                /* by the time we reach here q is initialized and handle is available.*/
4801                ia_css_bufq_enqueue_psys_event(
4802                    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4803                    (uint8_t)thread_id, 0,  0);
4804        }
4805
4806        /* in case of PREVIEW mode, check whether QOS acc_pipe is available, then start the qos pipe */
4807        if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
4808                struct ia_css_pipe *acc_pipe = NULL;
4809
4810                acc_pipe = pipe->pipe_settings.preview.acc_pipe;
4811
4812                if (acc_pipe) {
4813                        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(acc_pipe),
4814                                                         &thread_id);
4815                        /* by the time we reach here q is initialized and handle is available.*/
4816                        ia_css_bufq_enqueue_psys_event(
4817                            IA_CSS_PSYS_SW_EVENT_START_STREAM,
4818                            (uint8_t)thread_id, 0, 0);
4819                }
4820        }
4821
4822        stream->started = true;
4823
4824        IA_CSS_LEAVE_ERR_PRIVATE(err);
4825        return err;
4826}
4827
4828/* ISP2400 */
4829void
4830sh_css_enable_cont_capt(bool enable, bool stop_copy_preview)
4831{
4832        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4833                            "sh_css_enable_cont_capt() enter: enable=%d\n", enable);
4834//my_css.cont_capt = enable;
4835        my_css.stop_copy_preview = stop_copy_preview;
4836}
4837
4838bool
4839sh_css_continuous_is_enabled(uint8_t pipe_num)
4840{
4841        struct ia_css_pipe *pipe;
4842        bool continuous;
4843
4844        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4845                            "sh_css_continuous_is_enabled() enter: pipe_num=%d\n", pipe_num);
4846
4847        pipe = find_pipe_by_num(pipe_num);
4848        continuous = pipe && pipe->stream->config.continuous;
4849        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4850                            "sh_css_continuous_is_enabled() leave: enable=%d\n",
4851                            continuous);
4852        return continuous;
4853}
4854
4855/* ISP2400 */
4856int
4857ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream,
4858                                   int *buffer_depth)
4859{
4860        if (!buffer_depth)
4861                return -EINVAL;
4862        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_max_buffer_depth() enter: void\n");
4863        (void)stream;
4864        *buffer_depth = NUM_CONTINUOUS_FRAMES;
4865        return 0;
4866}
4867
4868int
4869ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth)
4870{
4871        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_set_buffer_depth() enter: num_frames=%d\n", buffer_depth);
4872        (void)stream;
4873        if (buffer_depth > NUM_CONTINUOUS_FRAMES || buffer_depth < 1)
4874                return -EINVAL;
4875        /* ok, value allowed */
4876        stream->config.target_num_cont_raw_buf = buffer_depth;
4877        /* TODO: check what to regarding initialization */
4878        return 0;
4879}
4880
4881/* ISP2401 */
4882int
4883ia_css_stream_get_buffer_depth(struct ia_css_stream *stream,
4884                               int *buffer_depth)
4885{
4886        if (!buffer_depth)
4887                return -EINVAL;
4888        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_buffer_depth() enter: void\n");
4889        (void)stream;
4890        *buffer_depth = stream->config.target_num_cont_raw_buf;
4891        return 0;
4892}
4893
4894/*
4895 * @brief Stop all "ia_css_pipe" instances in the target
4896 * "ia_css_stream" instance.
4897 *
4898 * Refer to "Local prototypes" for more info.
4899 */
4900/* ISP2401 */
4901static int
4902sh_css_pipes_stop(struct ia_css_stream *stream)
4903{
4904        int err = 0;
4905        struct ia_css_pipe *main_pipe;
4906        enum ia_css_pipe_id main_pipe_id;
4907        int i;
4908
4909        if (!stream) {
4910                IA_CSS_LOG("stream does NOT exist!");
4911                err = -EINVAL;
4912                goto ERR;
4913        }
4914
4915        main_pipe = stream->last_pipe;
4916        if (!main_pipe) {
4917                IA_CSS_LOG("main_pipe does NOT exist!");
4918                err = -EINVAL;
4919                goto ERR;
4920        }
4921
4922        main_pipe_id = main_pipe->mode;
4923        IA_CSS_ENTER_PRIVATE("main_pipe_id=%d", main_pipe_id);
4924
4925        /*
4926         * Stop all "ia_css_pipe" instances in this target
4927         * "ia_css_stream" instance.
4928         */
4929        for (i = 0; i < stream->num_pipes; i++) {
4930                /* send the "stop" request to the "ia_css_pipe" instance */
4931                IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d",
4932                           stream->pipes[i]->pipeline.pipe_id);
4933                err = ia_css_pipeline_request_stop(&stream->pipes[i]->pipeline);
4934
4935                /*
4936                * Exit this loop if "ia_css_pipeline_request_stop()"
4937                * returns the error code.
4938                *
4939                * The error code would be generated in the following
4940                * two cases:
4941                * (1) The Scalar Processor has already been stopped.
4942                * (2) The "Host->SP" event queue is full.
4943                *
4944                * As the convention of using CSS API 2.0/2.1, such CSS
4945                * error code would be propogated from the CSS-internal
4946                * API returned value to the CSS API returned value. Then
4947                * the CSS driver should capture these error code and
4948                * handle it in the driver exception handling mechanism.
4949                */
4950                if (err)
4951                        goto ERR;
4952        }
4953
4954        /*
4955         * In the CSS firmware use scenario "Continuous Preview"
4956         * as well as "Continuous Video", the "ia_css_pipe" instance
4957         * "Copy Pipe" is activated. This "Copy Pipe" is private to
4958         * the CSS firmware so that it is not listed in the target
4959         * "ia_css_stream" instance.
4960         *
4961         * We need to stop this "Copy Pipe", as well.
4962         */
4963        if (main_pipe->stream->config.continuous) {
4964                struct ia_css_pipe *copy_pipe = NULL;
4965
4966                /* get the reference to "Copy Pipe" */
4967                if (main_pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4968                        copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
4969                else if (main_pipe_id == IA_CSS_PIPE_ID_VIDEO)
4970                        copy_pipe = main_pipe->pipe_settings.video.copy_pipe;
4971
4972                /* return the error code if "Copy Pipe" does NOT exist */
4973                if (!copy_pipe) {
4974                        IA_CSS_LOG("Copy Pipe does NOT exist!");
4975                        err = -EINVAL;
4976                        goto ERR;
4977                }
4978
4979                /* send the "stop" request to "Copy Pipe" */
4980                IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d",
4981                           copy_pipe->pipeline.pipe_id);
4982                err = ia_css_pipeline_request_stop(&copy_pipe->pipeline);
4983        }
4984
4985ERR:
4986        IA_CSS_LEAVE_ERR_PRIVATE(err);
4987        return err;
4988}
4989
4990/*
4991 * @brief Check if all "ia_css_pipe" instances in the target
4992 * "ia_css_stream" instance have stopped.
4993 *
4994 * Refer to "Local prototypes" for more info.
4995 */
4996/* ISP2401 */
4997static bool
4998sh_css_pipes_have_stopped(struct ia_css_stream *stream)
4999{
5000        bool rval = true;
5001
5002        struct ia_css_pipe *main_pipe;
5003        enum ia_css_pipe_id main_pipe_id;
5004
5005        int i;
5006
5007        if (!stream) {
5008                IA_CSS_LOG("stream does NOT exist!");
5009                rval = false;
5010                goto RET;
5011        }
5012
5013        main_pipe = stream->last_pipe;
5014
5015        if (!main_pipe) {
5016                IA_CSS_LOG("main_pipe does NOT exist!");
5017                rval = false;
5018                goto RET;
5019        }
5020
5021        main_pipe_id = main_pipe->mode;
5022        IA_CSS_ENTER_PRIVATE("main_pipe_id=%d", main_pipe_id);
5023
5024        /*
5025         * Check if every "ia_css_pipe" instance in this target
5026         * "ia_css_stream" instance has stopped.
5027         */
5028        for (i = 0; i < stream->num_pipes; i++) {
5029                rval = rval && ia_css_pipeline_has_stopped(&stream->pipes[i]->pipeline);
5030                IA_CSS_LOG("Pipe has stopped: pipe_id=%d, stopped=%d",
5031                           stream->pipes[i]->pipeline.pipe_id,
5032                           rval);
5033        }
5034
5035        /*
5036         * In the CSS firmware use scenario "Continuous Preview"
5037         * as well as "Continuous Video", the "ia_css_pipe" instance
5038         * "Copy Pipe" is activated. This "Copy Pipe" is private to
5039         * the CSS firmware so that it is not listed in the target
5040         * "ia_css_stream" instance.
5041         *
5042         * We need to check if this "Copy Pipe" has stopped, as well.
5043         */
5044        if (main_pipe->stream->config.continuous) {
5045                struct ia_css_pipe *copy_pipe = NULL;
5046
5047                /* get the reference to "Copy Pipe" */
5048                if (main_pipe_id == IA_CSS_PIPE_ID_PREVIEW)
5049                        copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
5050                else if (main_pipe_id == IA_CSS_PIPE_ID_VIDEO)
5051                        copy_pipe = main_pipe->pipe_settings.video.copy_pipe;
5052
5053                /* return if "Copy Pipe" does NOT exist */
5054                if (!copy_pipe) {
5055                        IA_CSS_LOG("Copy Pipe does NOT exist!");
5056
5057                        rval = false;
5058                        goto RET;
5059                }
5060
5061                /* check if "Copy Pipe" has stopped or not */
5062                rval = rval && ia_css_pipeline_has_stopped(&copy_pipe->pipeline);
5063                IA_CSS_LOG("Pipe has stopped: pipe_id=%d, stopped=%d",
5064                           copy_pipe->pipeline.pipe_id,
5065                           rval);
5066        }
5067
5068RET:
5069        IA_CSS_LEAVE_PRIVATE("rval=%d", rval);
5070        return rval;
5071}
5072
5073#if !defined(ISP2401)
5074unsigned int
5075sh_css_get_mipi_sizes_for_check(const unsigned int port, const unsigned int idx)
5076{
5077        OP___assert(port < N_CSI_PORTS);
5078        OP___assert(idx  < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT);
5079        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5080                            "sh_css_get_mipi_sizes_for_check(port %d, idx %d): %d\n",
5081                            port, idx, my_css.mipi_sizes_for_check[port][idx]);
5082        return my_css.mipi_sizes_for_check[port][idx];
5083}
5084#endif
5085
5086static int sh_css_pipe_configure_output(
5087    struct ia_css_pipe *pipe,
5088    unsigned int width,
5089    unsigned int height,
5090    unsigned int padded_width,
5091    enum ia_css_frame_format format,
5092    unsigned int idx)
5093{
5094        int err = 0;
5095
5096        IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, padded width = %d, format = %d, idx = %d",
5097                             pipe, width, height, padded_width, format, idx);
5098        if (!pipe) {
5099                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5100                return -EINVAL;
5101        }
5102
5103        err = ia_css_util_check_res(width, height);
5104        if (err) {
5105                IA_CSS_LEAVE_ERR_PRIVATE(err);
5106                return err;
5107        }
5108        if (pipe->output_info[idx].res.width != width ||
5109            pipe->output_info[idx].res.height != height ||
5110            pipe->output_info[idx].format != format) {
5111                ia_css_frame_info_init(
5112                    &pipe->output_info[idx],
5113                    width,
5114                    height,
5115                    format,
5116                    padded_width);
5117        }
5118        IA_CSS_LEAVE_ERR_PRIVATE(0);
5119        return 0;
5120}
5121
5122static int
5123sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe,
5124                             struct ia_css_shading_info *shading_info,
5125                             struct ia_css_pipe_config *pipe_config)
5126{
5127        int err = 0;
5128        struct ia_css_binary *binary = NULL;
5129
5130        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5131                            "sh_css_pipe_get_shading_info() enter:\n");
5132
5133        binary = ia_css_pipe_get_shading_correction_binary(pipe);
5134
5135        if (binary) {
5136                err = ia_css_binary_get_shading_info(binary,
5137                                                     IA_CSS_SHADING_CORRECTION_TYPE_1,
5138                                                     pipe->required_bds_factor,
5139                                                     (const struct ia_css_stream_config *)&pipe->stream->config,
5140                                                     shading_info, pipe_config);
5141
5142                /* Other function calls can be added here when other shading correction types will be added
5143                 * in the future.
5144                 */
5145        } else {
5146                /* When the pipe does not have a binary which has the shading
5147                 * correction, this function does not need to fill the shading
5148                 * information. It is not a error case, and then
5149                 * this function should return 0.
5150                 */
5151                memset(shading_info, 0, sizeof(*shading_info));
5152        }
5153        return err;
5154}
5155
5156static int
5157sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe,
5158                          struct ia_css_grid_info *info)
5159{
5160        int err = 0;
5161        struct ia_css_binary *binary = NULL;
5162
5163        assert(pipe);
5164        assert(info);
5165
5166        IA_CSS_ENTER_PRIVATE("");
5167
5168        binary = ia_css_pipe_get_s3a_binary(pipe);
5169
5170        if (binary) {
5171                err = ia_css_binary_3a_grid_info(binary, info, pipe);
5172                if (err)
5173                        goto ERR;
5174        } else {
5175                memset(&info->s3a_grid, 0, sizeof(info->s3a_grid));
5176        }
5177
5178        binary = ia_css_pipe_get_sdis_binary(pipe);
5179
5180        if (binary) {
5181                ia_css_binary_dvs_grid_info(binary, info, pipe);
5182                ia_css_binary_dvs_stat_grid_info(binary, info, pipe);
5183        } else {
5184                memset(&info->dvs_grid.dvs_grid_info, 0,
5185                       sizeof(info->dvs_grid.dvs_grid_info));
5186                memset(&info->dvs_grid.dvs_stat_grid_info, 0,
5187                       sizeof(info->dvs_grid.dvs_stat_grid_info));
5188        }
5189
5190        if (binary) {
5191                /* copy pipe does not have ISP binary*/
5192                info->isp_in_width = binary->internal_frame_info.res.width;
5193                info->isp_in_height = binary->internal_frame_info.res.height;
5194        }
5195
5196        info->vamem_type = IA_CSS_VAMEM_TYPE_2;
5197
5198ERR :
5199        IA_CSS_LEAVE_ERR_PRIVATE(err);
5200        return err;
5201}
5202
5203/* ISP2401 */
5204/*
5205 * @brief Check if a format is supported by the pipe.
5206 *
5207 */
5208static int
5209ia_css_pipe_check_format(struct ia_css_pipe *pipe,
5210                         enum ia_css_frame_format format)
5211{
5212        const enum ia_css_frame_format *supported_formats;
5213        int number_of_formats;
5214        int found = 0;
5215        int i;
5216
5217        IA_CSS_ENTER_PRIVATE("");
5218
5219        if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info) {
5220                IA_CSS_ERROR("Pipe or binary info is not set");
5221                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5222                return -EINVAL;
5223        }
5224
5225        supported_formats = pipe->pipe_settings.video.video_binary.info->output_formats;
5226        number_of_formats = sizeof(pipe->pipe_settings.video.video_binary.info->output_formats) / sizeof(enum ia_css_frame_format);
5227
5228        for (i = 0; i < number_of_formats && !found; i++) {
5229                if (supported_formats[i] == format) {
5230                        found = 1;
5231                        break;
5232                }
5233        }
5234        if (!found) {
5235                IA_CSS_ERROR("Requested format is not supported by binary");
5236                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5237                return -EINVAL;
5238        }
5239        IA_CSS_LEAVE_ERR_PRIVATE(0);
5240        return 0;
5241}
5242
5243static int load_video_binaries(struct ia_css_pipe *pipe)
5244{
5245        struct ia_css_frame_info video_in_info, tnr_info,
5246                       *video_vf_info, video_bds_out_info, *pipe_out_info, *pipe_vf_out_info;
5247        bool online;
5248        int err = 0;
5249        bool continuous = pipe->stream->config.continuous;
5250        unsigned int i;
5251        unsigned int num_output_pins;
5252        struct ia_css_frame_info video_bin_out_info;
5253        bool need_scaler = false;
5254        bool vf_res_different_than_output = false;
5255        bool need_vf_pp = false;
5256        int vf_ds_log2;
5257        struct ia_css_video_settings *mycs  = &pipe->pipe_settings.video;
5258
5259        IA_CSS_ENTER_PRIVATE("");
5260        assert(pipe);
5261        assert(pipe->mode == IA_CSS_PIPE_ID_VIDEO);
5262        /* we only test the video_binary because offline video doesn't need a
5263         * vf_pp binary and online does not (always use) the copy_binary.
5264         * All are always reset at the same time anyway.
5265         */
5266        if (mycs->video_binary.info)
5267                return 0;
5268
5269        online = pipe->stream->config.online;
5270        pipe_out_info = &pipe->output_info[0];
5271        pipe_vf_out_info = &pipe->vf_output_info[0];
5272
5273        assert(pipe_out_info);
5274
5275        /*
5276         * There is no explicit input format requirement for raw or yuv
5277         * What matters is that there is a binary that supports the stream format.
5278         * This is checked in the binary_find(), so no need to check it here
5279         */
5280        err = ia_css_util_check_input(&pipe->stream->config, false, false);
5281        if (err)
5282                return err;
5283        /* cannot have online video and input_mode memory */
5284        if (online && pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY)
5285                return -EINVAL;
5286        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5287                err = ia_css_util_check_vf_out_info(pipe_out_info,
5288                                                    pipe_vf_out_info);
5289                if (err)
5290                        return err;
5291        } else {
5292                err = ia_css_frame_check_info(pipe_out_info);
5293                if (err)
5294                        return err;
5295        }
5296
5297        if (pipe->out_yuv_ds_input_info.res.width)
5298                video_bin_out_info = pipe->out_yuv_ds_input_info;
5299        else
5300                video_bin_out_info = *pipe_out_info;
5301
5302        /* Video */
5303        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5304                video_vf_info = pipe_vf_out_info;
5305                vf_res_different_than_output = (video_vf_info->res.width !=
5306                                                video_bin_out_info.res.width) ||
5307                                               (video_vf_info->res.height != video_bin_out_info.res.height);
5308        } else {
5309                video_vf_info = NULL;
5310        }
5311
5312        need_scaler = need_downscaling(video_bin_out_info.res, pipe_out_info->res);
5313
5314        /* we build up the pipeline starting at the end */
5315        /* YUV post-processing if needed */
5316        if (need_scaler) {
5317                struct ia_css_cas_binary_descr cas_scaler_descr = { };
5318
5319                /* NV12 is the common format that is supported by both */
5320                /* yuv_scaler and the video_xx_isp2_min binaries. */
5321                video_bin_out_info.format = IA_CSS_FRAME_FORMAT_NV12;
5322
5323                err = ia_css_pipe_create_cas_scaler_desc_single_output(
5324                          &video_bin_out_info,
5325                          pipe_out_info,
5326                          NULL,
5327                          &cas_scaler_descr);
5328                if (err)
5329                        return err;
5330                mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
5331                mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage *
5332                                                  sizeof(struct ia_css_binary), GFP_KERNEL);
5333                if (!mycs->yuv_scaler_binary) {
5334                        err = -ENOMEM;
5335                        return err;
5336                }
5337                mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage
5338                                                * sizeof(bool), GFP_KERNEL);
5339                if (!mycs->is_output_stage) {
5340                        err = -ENOMEM;
5341                        return err;
5342                }
5343                for (i = 0; i < cas_scaler_descr.num_stage; i++) {
5344                        struct ia_css_binary_descr yuv_scaler_descr;
5345
5346                        mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
5347                        ia_css_pipe_get_yuvscaler_binarydesc(pipe,
5348                                                             &yuv_scaler_descr, &cas_scaler_descr.in_info[i],
5349                                                             &cas_scaler_descr.out_info[i],
5350                                                             &cas_scaler_descr.internal_out_info[i],
5351                                                             &cas_scaler_descr.vf_info[i]);
5352                        err = ia_css_binary_find(&yuv_scaler_descr,
5353                                                 &mycs->yuv_scaler_binary[i]);
5354                        if (err) {
5355                                kfree(mycs->is_output_stage);
5356                                mycs->is_output_stage = NULL;
5357                                return err;
5358                        }
5359                }
5360                ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
5361        }
5362
5363        {
5364                struct ia_css_binary_descr video_descr;
5365                enum ia_css_frame_format vf_info_format;
5366
5367                err = ia_css_pipe_get_video_binarydesc(pipe,
5368                                                       &video_descr, &video_in_info, &video_bds_out_info, &video_bin_out_info,
5369                                                       video_vf_info,
5370                                                       pipe->stream->config.left_padding);
5371                if (err)
5372                        return err;
5373
5374                /* In the case where video_vf_info is not NULL, this allows
5375                 * us to find a potential video library with desired vf format.
5376                 * If success, no vf_pp binary is needed.
5377                 * If failed, we will look up video binary with YUV_LINE vf format
5378                 */
5379                err = ia_css_binary_find(&video_descr,
5380                                         &mycs->video_binary);
5381
5382                if (err) {
5383                        /* This will do another video binary lookup later for YUV_LINE format*/
5384                        if (video_vf_info)
5385                                need_vf_pp = true;
5386                        else
5387                                return err;
5388                } else if (video_vf_info) {
5389                        /* The first video binary lookup is successful, but we may
5390                         * still need vf_pp binary based on additiona check */
5391                        num_output_pins = mycs->video_binary.info->num_output_pins;
5392                        vf_ds_log2 = mycs->video_binary.vf_downscale_log2;
5393
5394                        /* If the binary has dual output pins, we need vf_pp if the resolution
5395                        * is different. */
5396                        need_vf_pp |= ((num_output_pins == 2) && vf_res_different_than_output);
5397
5398                        /* If the binary has single output pin, we need vf_pp if additional
5399                        * scaling is needed for vf */
5400                        need_vf_pp |= ((num_output_pins == 1) &&
5401                                       ((video_vf_info->res.width << vf_ds_log2 != pipe_out_info->res.width) ||
5402                                        (video_vf_info->res.height << vf_ds_log2 != pipe_out_info->res.height)));
5403                }
5404
5405                if (need_vf_pp) {
5406                        /* save the current vf_info format for restoration later */
5407                        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
5408                                            "load_video_binaries() need_vf_pp; find video binary with YUV_LINE again\n");
5409
5410                        vf_info_format = video_vf_info->format;
5411
5412                        if (!pipe->config.enable_vfpp_bci)
5413                                ia_css_frame_info_set_format(video_vf_info,
5414                                                             IA_CSS_FRAME_FORMAT_YUV_LINE);
5415
5416                        ia_css_binary_destroy_isp_parameters(&mycs->video_binary);
5417
5418                        err = ia_css_binary_find(&video_descr,
5419                                                 &mycs->video_binary);
5420
5421                        /* restore original vf_info format */
5422                        ia_css_frame_info_set_format(video_vf_info,
5423                                                     vf_info_format);
5424                        if (err)
5425                                return err;
5426                }
5427        }
5428
5429        /* If a video binary does not use a ref_frame, we set the frame delay
5430         * to 0. This is the case for the 1-stage low-power video binary. */
5431        if (!mycs->video_binary.info->sp.enable.ref_frame)
5432                pipe->dvs_frame_delay = 0;
5433
5434        /* The delay latency determines the number of invalid frames after
5435         * a stream is started. */
5436        pipe->num_invalid_frames = pipe->dvs_frame_delay;
5437        pipe->info.num_invalid_frames = pipe->num_invalid_frames;
5438
5439        /* Viewfinder frames also decrement num_invalid_frames. If the pipe
5440         * outputs a viewfinder output, then we need double the number of
5441         * invalid frames */
5442        if (video_vf_info)
5443                pipe->num_invalid_frames *= 2;
5444
5445        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
5446                            "load_video_binaries() num_invalid_frames=%d dvs_frame_delay=%d\n",
5447                            pipe->num_invalid_frames, pipe->dvs_frame_delay);
5448
5449        /* pqiao TODO: temp hack for PO, should be removed after offline YUVPP is enabled */
5450#if !defined(ISP2401)
5451        /* Copy */
5452        if (!online && !continuous) {
5453                /* TODO: what exactly needs doing, prepend the copy binary to
5454                 *       video base this only on !online?
5455                 */
5456                err = load_copy_binary(pipe,
5457                                       &mycs->copy_binary,
5458                                       &mycs->video_binary);
5459                if (err)
5460                        return err;
5461        }
5462#else
5463        (void)continuous;
5464#endif
5465
5466#if !defined(HAS_OUTPUT_SYSTEM)
5467        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] && need_vf_pp) {
5468                struct ia_css_binary_descr vf_pp_descr;
5469
5470                if (mycs->video_binary.vf_frame_info.format
5471                    == IA_CSS_FRAME_FORMAT_YUV_LINE) {
5472                        ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
5473                                                        &mycs->video_binary.vf_frame_info,
5474                                                        pipe_vf_out_info);
5475                } else {
5476                        /* output from main binary is not yuv line. currently this is
5477                         * possible only when bci is enabled on vfpp output */
5478                        assert(pipe->config.enable_vfpp_bci);
5479                        ia_css_pipe_get_yuvscaler_binarydesc(pipe, &vf_pp_descr,
5480                                                             &mycs->video_binary.vf_frame_info,
5481                                                             pipe_vf_out_info, NULL, NULL);
5482                }
5483
5484                err = ia_css_binary_find(&vf_pp_descr,
5485                                         &mycs->vf_pp_binary);
5486                if (err)
5487                        return err;
5488        }
5489#endif
5490
5491        err = allocate_delay_frames(pipe);
5492
5493        if (err)
5494                return err;
5495
5496        if (mycs->video_binary.info->sp.enable.block_output) {
5497                unsigned int tnr_width;
5498                unsigned int tnr_height;
5499
5500                tnr_info = mycs->video_binary.out_frame_info[0];
5501
5502                if (IS_ISP2401) {
5503                        /* Select resolution for TNR. If
5504                        * output_system_in_resolution(GDC_out_resolution) is
5505                        * being used, then select that as it will also be in resolution for
5506                        * TNR. At present, it only make sense for Skycam */
5507                        if (pipe->config.output_system_in_res.width &&
5508                            pipe->config.output_system_in_res.height) {
5509                                tnr_width = pipe->config.output_system_in_res.width;
5510                                tnr_height = pipe->config.output_system_in_res.height;
5511                        } else {
5512                                tnr_width = tnr_info.res.width;
5513                                tnr_height = tnr_info.res.height;
5514                        }
5515
5516                        /* Make tnr reference buffers output block width(in pix) align */
5517                        tnr_info.res.width  = CEIL_MUL(tnr_width,
5518                                                       (mycs->video_binary.info->sp.block.block_width * ISP_NWAY));
5519                        tnr_info.padded_width = tnr_info.res.width;
5520                } else {
5521                        tnr_height = tnr_info.res.height;
5522                }
5523
5524                /* Make tnr reference buffers output block height align */
5525                tnr_info.res.height = CEIL_MUL(tnr_height,
5526                                               mycs->video_binary.info->sp.block.output_block_height);
5527        } else {
5528                tnr_info = mycs->video_binary.internal_frame_info;
5529        }
5530        tnr_info.format = IA_CSS_FRAME_FORMAT_YUV_LINE;
5531        tnr_info.raw_bit_depth = SH_CSS_TNR_BIT_DEPTH;
5532
5533        for (i = 0; i < NUM_TNR_FRAMES; i++) {
5534                if (mycs->tnr_frames[i]) {
5535                        ia_css_frame_free(mycs->tnr_frames[i]);
5536                        mycs->tnr_frames[i] = NULL;
5537                }
5538                err = ia_css_frame_allocate_from_info(
5539                          &mycs->tnr_frames[i],
5540                          &tnr_info);
5541                if (err)
5542                        return err;
5543        }
5544        IA_CSS_LEAVE_PRIVATE("");
5545        return 0;
5546}
5547
5548static int
5549unload_video_binaries(struct ia_css_pipe *pipe)
5550{
5551        unsigned int i;
5552
5553        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
5554
5555        if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
5556                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5557                return -EINVAL;
5558        }
5559        ia_css_binary_unload(&pipe->pipe_settings.video.copy_binary);
5560        ia_css_binary_unload(&pipe->pipe_settings.video.video_binary);
5561        ia_css_binary_unload(&pipe->pipe_settings.video.vf_pp_binary);
5562
5563        for (i = 0; i < pipe->pipe_settings.video.num_yuv_scaler; i++)
5564                ia_css_binary_unload(&pipe->pipe_settings.video.yuv_scaler_binary[i]);
5565
5566        kfree(pipe->pipe_settings.video.is_output_stage);
5567        pipe->pipe_settings.video.is_output_stage = NULL;
5568        kfree(pipe->pipe_settings.video.yuv_scaler_binary);
5569        pipe->pipe_settings.video.yuv_scaler_binary = NULL;
5570
5571        IA_CSS_LEAVE_ERR_PRIVATE(0);
5572        return 0;
5573}
5574
5575static int video_start(struct ia_css_pipe *pipe)
5576{
5577        int err = 0;
5578        struct ia_css_pipe *copy_pipe, *capture_pipe;
5579        enum sh_css_pipe_config_override copy_ovrd;
5580        enum ia_css_input_mode video_pipe_input_mode;
5581
5582        const struct ia_css_coordinate *coord = NULL;
5583        const struct ia_css_isp_parameters *params = NULL;
5584
5585        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
5586        if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
5587                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5588                return -EINVAL;
5589        }
5590
5591        video_pipe_input_mode = pipe->stream->config.mode;
5592
5593        copy_pipe    = pipe->pipe_settings.video.copy_pipe;
5594        capture_pipe = pipe->pipe_settings.video.capture_pipe;
5595
5596        sh_css_metrics_start_frame();
5597
5598        /* multi stream video needs mipi buffers */
5599
5600        err = send_mipi_frames(pipe);
5601        if (err)
5602                return err;
5603
5604        send_raw_frames(pipe);
5605        {
5606                unsigned int thread_id;
5607
5608                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
5609                copy_ovrd = 1 << thread_id;
5610
5611                if (pipe->stream->cont_capt) {
5612                        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
5613                                                         &thread_id);
5614                        copy_ovrd |= 1 << thread_id;
5615                }
5616        }
5617
5618        if (IS_ISP2401) {
5619                coord = &pipe->config.internal_frame_origin_bqs_on_sctbl;
5620                params = pipe->stream->isp_params_configs;
5621        }
5622
5623        /* Construct and load the copy pipe */
5624        if (pipe->stream->config.continuous) {
5625                sh_css_sp_init_pipeline(&copy_pipe->pipeline,
5626                                        IA_CSS_PIPE_ID_COPY,
5627                                        (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
5628                                        false,
5629                                        pipe->stream->config.pixels_per_clock == 2, false,
5630                                        false, pipe->required_bds_factor,
5631                                        copy_ovrd,
5632                                        pipe->stream->config.mode,
5633                                        &pipe->stream->config.metadata_config,
5634                                        &pipe->stream->info.metadata_info,
5635                                        pipe->stream->config.source.port.port,
5636                                        coord,
5637                                        params);
5638
5639                /* make the video pipe start with mem mode input, copy handles
5640                   the actual mode */
5641                video_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY;
5642        }
5643
5644        /* Construct and load the capture pipe */
5645        if (pipe->stream->cont_capt) {
5646                sh_css_sp_init_pipeline(&capture_pipe->pipeline,
5647                                        IA_CSS_PIPE_ID_CAPTURE,
5648                                        (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
5649                                        capture_pipe->config.default_capture_config.enable_xnr != 0,
5650                                        capture_pipe->stream->config.pixels_per_clock == 2,
5651                                        true, /* continuous */
5652                                        false, /* offline */
5653                                        capture_pipe->required_bds_factor,
5654                                        0,
5655                                        IA_CSS_INPUT_MODE_MEMORY,
5656                                        &pipe->stream->config.metadata_config,
5657                                        &pipe->stream->info.metadata_info,
5658                                        (enum mipi_port_id)0,
5659                                        coord,
5660                                        params);
5661        }
5662
5663        start_pipe(pipe, copy_ovrd, video_pipe_input_mode);
5664
5665        IA_CSS_LEAVE_ERR_PRIVATE(err);
5666        return err;
5667}
5668
5669static
5670int sh_css_pipe_get_viewfinder_frame_info(
5671    struct ia_css_pipe *pipe,
5672    struct ia_css_frame_info *info,
5673    unsigned int idx)
5674{
5675        assert(pipe);
5676        assert(info);
5677
5678        /* We could print the pointer as input arg, and the values as output */
5679        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5680                            "sh_css_pipe_get_viewfinder_frame_info() enter: void\n");
5681
5682        if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE &&
5683            (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW ||
5684             pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER))
5685                return -EINVAL;
5686        /* offline video does not generate viewfinder output */
5687        *info = pipe->vf_output_info[idx];
5688
5689        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5690                            "sh_css_pipe_get_viewfinder_frame_info() leave: \
5691                info.res.width=%d, info.res.height=%d, \
5692                info.padded_width=%d, info.format=%d, \
5693                info.raw_bit_depth=%d, info.raw_bayer_order=%d\n",
5694                            info->res.width, info->res.height,
5695                            info->padded_width, info->format,
5696                            info->raw_bit_depth, info->raw_bayer_order);
5697
5698        return 0;
5699}
5700
5701static int
5702sh_css_pipe_configure_viewfinder(struct ia_css_pipe *pipe, unsigned int width,
5703                                 unsigned int height, unsigned int min_width,
5704                                 enum ia_css_frame_format format,
5705                                 unsigned int idx)
5706{
5707        int err = 0;
5708
5709        IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, min_width = %d, format = %d, idx = %d\n",
5710                             pipe, width, height, min_width, format, idx);
5711
5712        if (!pipe) {
5713                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5714                return -EINVAL;
5715        }
5716
5717        err = ia_css_util_check_res(width, height);
5718        if (err) {
5719                IA_CSS_LEAVE_ERR_PRIVATE(err);
5720                return err;
5721        }
5722        if (pipe->vf_output_info[idx].res.width != width ||
5723            pipe->vf_output_info[idx].res.height != height ||
5724            pipe->vf_output_info[idx].format != format)
5725                ia_css_frame_info_init(&pipe->vf_output_info[idx], width, height,
5726                                       format, min_width);
5727
5728        IA_CSS_LEAVE_ERR_PRIVATE(0);
5729        return 0;
5730}
5731
5732static int load_copy_binaries(struct ia_css_pipe *pipe)
5733{
5734        int err = 0;
5735
5736        assert(pipe);
5737        IA_CSS_ENTER_PRIVATE("");
5738
5739        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5740               pipe->mode == IA_CSS_PIPE_ID_COPY);
5741        if (pipe->pipe_settings.capture.copy_binary.info)
5742                return 0;
5743
5744        err = ia_css_frame_check_info(&pipe->output_info[0]);
5745        if (err)
5746                goto ERR;
5747
5748        err = verify_copy_out_frame_format(pipe);
5749        if (err)
5750                goto ERR;
5751
5752        err = load_copy_binary(pipe,
5753                               &pipe->pipe_settings.capture.copy_binary,
5754                               NULL);
5755
5756ERR:
5757        IA_CSS_LEAVE_ERR_PRIVATE(err);
5758        return err;
5759}
5760
5761static bool need_capture_pp(
5762    const struct ia_css_pipe *pipe)
5763{
5764        const struct ia_css_frame_info *out_info = &pipe->output_info[0];
5765
5766        IA_CSS_ENTER_LEAVE_PRIVATE("");
5767        assert(pipe);
5768        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
5769
5770        if (IS_ISP2401) {
5771                /* ldc and capture_pp are not supported in the same pipeline */
5772                if (need_capt_ldc(pipe))
5773                        return false;
5774        }
5775
5776        /* determine whether we need to use the capture_pp binary.
5777         * This is needed for:
5778         *   1. XNR or
5779         *   2. Digital Zoom or
5780         *   3. YUV downscaling
5781         */
5782        if (pipe->out_yuv_ds_input_info.res.width &&
5783            ((pipe->out_yuv_ds_input_info.res.width != out_info->res.width) ||
5784             (pipe->out_yuv_ds_input_info.res.height != out_info->res.height)))
5785                return true;
5786
5787        if (pipe->config.default_capture_config.enable_xnr != 0)
5788                return true;
5789
5790        if ((pipe->stream->isp_params_configs->dz_config.dx < HRT_GDC_N) ||
5791            (pipe->stream->isp_params_configs->dz_config.dy < HRT_GDC_N) ||
5792            pipe->config.enable_dz)
5793                return true;
5794
5795        return false;
5796}
5797
5798static bool need_capt_ldc(
5799    const struct ia_css_pipe *pipe)
5800{
5801        IA_CSS_ENTER_LEAVE_PRIVATE("");
5802        assert(pipe);
5803        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
5804        return (pipe->extra_config.enable_dvs_6axis) ? true : false;
5805}
5806
5807static int set_num_primary_stages(unsigned int *num,
5808                                  enum ia_css_pipe_version version)
5809{
5810        int err = 0;
5811
5812        if (!num)
5813                return -EINVAL;
5814
5815        switch (version) {
5816        case IA_CSS_PIPE_VERSION_2_6_1:
5817                *num = NUM_PRIMARY_HQ_STAGES;
5818                break;
5819        case IA_CSS_PIPE_VERSION_2_2:
5820        case IA_CSS_PIPE_VERSION_1:
5821                *num = NUM_PRIMARY_STAGES;
5822                break;
5823        default:
5824                err = -EINVAL;
5825                break;
5826        }
5827
5828        return err;
5829}
5830
5831static int load_primary_binaries(
5832    struct ia_css_pipe *pipe)
5833{
5834        bool online = false;
5835        bool need_pp = false;
5836        bool need_isp_copy_binary = false;
5837        bool need_ldc = false;
5838#ifdef ISP2401
5839        bool sensor = false;
5840#else
5841        bool memory, continuous;
5842#endif
5843        struct ia_css_frame_info prim_in_info,
5844                       prim_out_info,
5845                       capt_pp_out_info, vf_info,
5846                       *vf_pp_in_info, *pipe_out_info,
5847                       *pipe_vf_out_info, *capt_pp_in_info,
5848                       capt_ldc_out_info;
5849        int err = 0;
5850        struct ia_css_capture_settings *mycs;
5851        unsigned int i;
5852        bool need_extra_yuv_scaler = false;
5853        struct ia_css_binary_descr prim_descr[MAX_NUM_PRIMARY_STAGES];
5854
5855        IA_CSS_ENTER_PRIVATE("");
5856        assert(pipe);
5857        assert(pipe->stream);
5858        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5859               pipe->mode == IA_CSS_PIPE_ID_COPY);
5860
5861        online = pipe->stream->config.online;
5862#ifdef ISP2401
5863        sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
5864#else
5865        memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
5866        continuous = pipe->stream->config.continuous;
5867#endif
5868
5869        mycs = &pipe->pipe_settings.capture;
5870        pipe_out_info = &pipe->output_info[0];
5871        pipe_vf_out_info = &pipe->vf_output_info[0];
5872
5873        if (mycs->primary_binary[0].info)
5874                return 0;
5875
5876        err = set_num_primary_stages(&mycs->num_primary_stage,
5877                                     pipe->config.isp_pipe_version);
5878        if (err) {
5879                IA_CSS_LEAVE_ERR_PRIVATE(err);
5880                return err;
5881        }
5882
5883        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5884                err = ia_css_util_check_vf_out_info(pipe_out_info, pipe_vf_out_info);
5885                if (err) {
5886                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5887                        return err;
5888                }
5889        } else {
5890                err = ia_css_frame_check_info(pipe_out_info);
5891                if (err) {
5892                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5893                        return err;
5894                }
5895        }
5896        need_pp = need_capture_pp(pipe);
5897
5898        /* we use the vf output info to get the primary/capture_pp binary
5899           configured for vf_veceven. It will select the closest downscaling
5900           factor. */
5901        vf_info = *pipe_vf_out_info;
5902
5903        /*
5904         * WARNING: The #if def flag has been added below as a
5905         * temporary solution to solve the problem of enabling the
5906         * view finder in a single binary in a capture flow. The
5907         * vf-pp stage has been removed for Skycam in the solution
5908         * provided. The vf-pp stage should be re-introduced when
5909         * required. This should not be considered as a clean solution.
5910         * Proper investigation should be done to come up with the clean
5911         * solution.
5912         * */
5913        ia_css_frame_info_set_format(&vf_info, IA_CSS_FRAME_FORMAT_YUV_LINE);
5914
5915        /* TODO: All this yuv_scaler and capturepp calculation logic
5916         * can be shared later. Capture_pp is also a yuv_scale binary
5917         * with extra XNR funcionality. Therefore, it can be made as the
5918         * first step of the cascade. */
5919        capt_pp_out_info = pipe->out_yuv_ds_input_info;
5920        capt_pp_out_info.format = IA_CSS_FRAME_FORMAT_YUV420;
5921        capt_pp_out_info.res.width  /= MAX_PREFERRED_YUV_DS_PER_STEP;
5922        capt_pp_out_info.res.height /= MAX_PREFERRED_YUV_DS_PER_STEP;
5923        ia_css_frame_info_set_width(&capt_pp_out_info, capt_pp_out_info.res.width, 0);
5924
5925        need_extra_yuv_scaler = need_downscaling(capt_pp_out_info.res,
5926                                                 pipe_out_info->res);
5927
5928        if (need_extra_yuv_scaler) {
5929                struct ia_css_cas_binary_descr cas_scaler_descr = { };
5930
5931                err = ia_css_pipe_create_cas_scaler_desc_single_output(
5932                          &capt_pp_out_info,
5933                          pipe_out_info,
5934                          NULL,
5935                          &cas_scaler_descr);
5936                if (err) {
5937                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5938                        return err;
5939                }
5940                mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
5941                mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage *
5942                                                  sizeof(struct ia_css_binary), GFP_KERNEL);
5943                if (!mycs->yuv_scaler_binary) {
5944                        err = -ENOMEM;
5945                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5946                        return err;
5947                }
5948                mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage *
5949                                                sizeof(bool), GFP_KERNEL);
5950                if (!mycs->is_output_stage) {
5951                        err = -ENOMEM;
5952                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5953                        return err;
5954                }
5955                for (i = 0; i < cas_scaler_descr.num_stage; i++) {
5956                        struct ia_css_binary_descr yuv_scaler_descr;
5957
5958                        mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
5959                        ia_css_pipe_get_yuvscaler_binarydesc(pipe,
5960                                                             &yuv_scaler_descr, &cas_scaler_descr.in_info[i],
5961                                                             &cas_scaler_descr.out_info[i],
5962                                                             &cas_scaler_descr.internal_out_info[i],
5963                                                             &cas_scaler_descr.vf_info[i]);
5964                        err = ia_css_binary_find(&yuv_scaler_descr,
5965                                                 &mycs->yuv_scaler_binary[i]);
5966                        if (err) {
5967                                IA_CSS_LEAVE_ERR_PRIVATE(err);
5968                                return err;
5969                        }
5970                }
5971                ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
5972
5973        } else {
5974                capt_pp_out_info = pipe->output_info[0];
5975        }
5976
5977        /* TODO Do we disable ldc for skycam */
5978        need_ldc = need_capt_ldc(pipe);
5979        if (IS_ISP2401 && need_ldc) {
5980                /* ldc and capt_pp are not supported in the same pipeline */
5981                struct ia_css_binary_descr capt_ldc_descr;
5982
5983                ia_css_pipe_get_ldc_binarydesc(pipe,
5984                                               &capt_ldc_descr, &prim_out_info,
5985                                               &capt_pp_out_info);
5986
5987                err = ia_css_binary_find(&capt_ldc_descr,
5988                                         &mycs->capture_ldc_binary);
5989                if (err) {
5990                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5991                        return err;
5992                }
5993                need_pp = false;
5994                need_ldc = false;
5995        }
5996
5997        /* we build up the pipeline starting at the end */
5998        /* Capture post-processing */
5999        if (need_pp) {
6000                struct ia_css_binary_descr capture_pp_descr;
6001
6002                if (!IS_ISP2401)
6003                        capt_pp_in_info = need_ldc ? &capt_ldc_out_info : &prim_out_info;
6004                else
6005                        capt_pp_in_info = &prim_out_info;
6006
6007                ia_css_pipe_get_capturepp_binarydesc(pipe,
6008                                                     &capture_pp_descr,
6009                                                     capt_pp_in_info,
6010                                                     &capt_pp_out_info,
6011                                                     &vf_info);
6012
6013                err = ia_css_binary_find(&capture_pp_descr,
6014                                         &mycs->capture_pp_binary);
6015                if (err) {
6016                        IA_CSS_LEAVE_ERR_PRIVATE(err);
6017                        return err;
6018                }
6019
6020                if (need_ldc) {
6021                        struct ia_css_binary_descr capt_ldc_descr;
6022
6023                        ia_css_pipe_get_ldc_binarydesc(pipe,
6024                                                       &capt_ldc_descr,
6025                                                       &prim_out_info,
6026                                                       &capt_ldc_out_info);
6027
6028                        err = ia_css_binary_find(&capt_ldc_descr,
6029                                                 &mycs->capture_ldc_binary);
6030                        if (err) {
6031                                IA_CSS_LEAVE_ERR_PRIVATE(err);
6032                                return err;
6033                        }
6034                }
6035        } else {
6036                prim_out_info = *pipe_out_info;
6037        }
6038
6039        /* Primary */
6040        for (i = 0; i < mycs->num_primary_stage; i++) {
6041                struct ia_css_frame_info *local_vf_info = NULL;
6042
6043                if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] &&
6044                    (i == mycs->num_primary_stage - 1))
6045                        local_vf_info = &vf_info;
6046                ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i],
6047                                                   &prim_in_info, &prim_out_info,
6048                                                   local_vf_info, i);
6049                err = ia_css_binary_find(&prim_descr[i], &mycs->primary_binary[i]);
6050                if (err) {
6051                        IA_CSS_LEAVE_ERR_PRIVATE(err);
6052                        return err;
6053                }
6054        }
6055
6056        /* Viewfinder post-processing */
6057        if (need_pp)
6058                vf_pp_in_info = &mycs->capture_pp_binary.vf_frame_info;
6059        else
6060                vf_pp_in_info = &mycs->primary_binary[mycs->num_primary_stage - 1].vf_frame_info;
6061
6062        /*
6063            * WARNING: The #if def flag has been added below as a
6064            * temporary solution to solve the problem of enabling the
6065            * view finder in a single binary in a capture flow. The
6066            * vf-pp stage has been removed for Skycam in the solution
6067            * provided. The vf-pp stage should be re-introduced when
6068            * required. Thisshould not be considered as a clean solution.
6069            * Proper  * investigation should be done to come up with the clean
6070            * solution.
6071            * */
6072        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
6073                struct ia_css_binary_descr vf_pp_descr;
6074
6075                ia_css_pipe_get_vfpp_binarydesc(pipe,
6076                                                &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
6077                err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary);
6078                if (err) {
6079                        IA_CSS_LEAVE_ERR_PRIVATE(err);
6080                        return err;
6081                }
6082        }
6083        err = allocate_delay_frames(pipe);
6084
6085        if (err)
6086                return err;
6087
6088#ifdef ISP2401
6089        /* When the input system is 2401, only the Direct Sensor Mode
6090            * Offline Capture uses the ISP copy binary.
6091            */
6092        need_isp_copy_binary = !online && sensor;
6093#else
6094        need_isp_copy_binary = !online && !continuous && !memory;
6095#endif
6096
6097        /* ISP Copy */
6098        if (need_isp_copy_binary) {
6099                err = load_copy_binary(pipe,
6100                                       &mycs->copy_binary,
6101                                       &mycs->primary_binary[0]);
6102                if (err) {
6103                        IA_CSS_LEAVE_ERR_PRIVATE(err);
6104                        return err;
6105                }
6106        }
6107
6108        return 0;
6109}
6110
6111static int
6112allocate_delay_frames(struct ia_css_pipe *pipe)
6113{
6114        unsigned int num_delay_frames = 0, i = 0;
6115        unsigned int dvs_frame_delay = 0;
6116        struct ia_css_frame_info ref_info;
6117        int err = 0;
6118        enum ia_css_pipe_id mode = IA_CSS_PIPE_ID_VIDEO;
6119        struct ia_css_frame **delay_frames = NULL;
6120
6121        IA_CSS_ENTER_PRIVATE("");
6122
6123        if (!pipe) {
6124                IA_CSS_ERROR("Invalid args - pipe %p", pipe);
6125                return -EINVAL;
6126        }
6127
6128        mode = pipe->mode;
6129        dvs_frame_delay = pipe->dvs_frame_delay;
6130
6131        if (dvs_frame_delay > 0)
6132                num_delay_frames = dvs_frame_delay + 1;
6133
6134        switch (mode) {
6135        case IA_CSS_PIPE_ID_CAPTURE: {
6136                struct ia_css_capture_settings *mycs_capture = &pipe->pipe_settings.capture;
6137                (void)mycs_capture;
6138                return err;
6139        }
6140        break;
6141        case IA_CSS_PIPE_ID_VIDEO: {
6142                struct ia_css_video_settings *mycs_video = &pipe->pipe_settings.video;
6143
6144                ref_info = mycs_video->video_binary.internal_frame_info;
6145                /*The ref frame expects
6146                    *   1. Y plane
6147                    *   2. UV plane with line interleaving, like below
6148                    *           UUUUUU(width/2 times) VVVVVVVV..(width/2 times)
6149                    *
6150                    *   This format is not YUV420(which has Y, U and V planes).
6151                    *   Its closer to NV12, except that the UV plane has UV
6152                    *   interleaving, like UVUVUVUVUVUVUVUVU...
6153                    *
6154                    *   TODO: make this ref_frame format as a separate frame format
6155                    */
6156                ref_info.format        = IA_CSS_FRAME_FORMAT_NV12;
6157                delay_frames = mycs_video->delay_frames;
6158        }
6159        break;
6160        case IA_CSS_PIPE_ID_PREVIEW: {
6161                struct ia_css_preview_settings *mycs_preview = &pipe->pipe_settings.preview;
6162
6163                ref_info = mycs_preview->preview_binary.internal_frame_info;
6164                /*The ref frame expects
6165                    *   1. Y plane
6166                    *   2. UV plane with line interleaving, like below
6167                    *           UUUUUU(width/2 times) VVVVVVVV..(width/2 times)
6168                    *
6169                    *   This format is not YUV420(which has Y, U and V planes).
6170                    *   Its closer to NV12, except that the UV plane has UV
6171                    *   interleaving, like UVUVUVUVUVUVUVUVU...
6172                    *
6173                    *   TODO: make this ref_frame format as a separate frame format
6174                    */
6175                ref_info.format        = IA_CSS_FRAME_FORMAT_NV12;
6176                delay_frames = mycs_preview->delay_frames;
6177        }
6178        break;
6179        default:
6180                return -EINVAL;
6181        }
6182
6183        ref_info.raw_bit_depth = SH_CSS_REF_BIT_DEPTH;
6184
6185        assert(num_delay_frames <= MAX_NUM_VIDEO_DELAY_FRAMES);
6186        for (i = 0; i < num_delay_frames; i++) {
6187                err = ia_css_frame_allocate_from_info(&delay_frames[i], &ref_info);
6188                if (err)
6189                        return err;
6190        }
6191        IA_CSS_LEAVE_PRIVATE("");
6192        return 0;
6193}
6194
6195static int load_advanced_binaries(struct ia_css_pipe *pipe)
6196{
6197        struct ia_css_frame_info pre_in_info, gdc_in_info,
6198                        post_in_info, post_out_info,
6199                        vf_info, *vf_pp_in_info, *pipe_out_info,
6200                        *pipe_vf_out_info;
6201        bool need_pp;
6202        bool need_isp_copy = true;
6203        int err = 0;
6204
6205        IA_CSS_ENTER_PRIVATE("");
6206
6207        assert(pipe);
6208        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6209               pipe->mode == IA_CSS_PIPE_ID_COPY);
6210        if (pipe->pipe_settings.capture.pre_isp_binary.info)
6211                return 0;
6212        pipe_out_info = &pipe->output_info[0];
6213        pipe_vf_out_info = &pipe->vf_output_info[0];
6214
6215        vf_info = *pipe_vf_out_info;
6216        err = ia_css_util_check_vf_out_info(pipe_out_info, &vf_info);
6217        if (err)
6218                return err;
6219        need_pp = need_capture_pp(pipe);
6220
6221        ia_css_frame_info_set_format(&vf_info,
6222                                     IA_CSS_FRAME_FORMAT_YUV_LINE);
6223
6224        /* we build up the pipeline starting at the end */
6225        /* Capture post-processing */
6226        if (need_pp) {
6227                struct ia_css_binary_descr capture_pp_descr;
6228
6229                ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
6230                                                     &post_out_info,
6231                                                     pipe_out_info, &vf_info);
6232                err = ia_css_binary_find(&capture_pp_descr,
6233                                         &pipe->pipe_settings.capture.capture_pp_binary);
6234                if (err)
6235                        return err;
6236        } else {
6237                post_out_info = *pipe_out_info;
6238        }
6239
6240        /* Post-gdc */
6241        {
6242                struct ia_css_binary_descr post_gdc_descr;
6243
6244                ia_css_pipe_get_post_gdc_binarydesc(pipe, &post_gdc_descr,
6245                                                    &post_in_info,
6246                                                    &post_out_info, &vf_info);
6247                err = ia_css_binary_find(&post_gdc_descr,
6248                                         &pipe->pipe_settings.capture.post_isp_binary);
6249                if (err)
6250                        return err;
6251        }
6252
6253        /* Gdc */
6254        {
6255                struct ia_css_binary_descr gdc_descr;
6256
6257                ia_css_pipe_get_gdc_binarydesc(pipe, &gdc_descr, &gdc_in_info,
6258                                               &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
6259                err = ia_css_binary_find(&gdc_descr,
6260                                         &pipe->pipe_settings.capture.anr_gdc_binary);
6261                if (err)
6262                        return err;
6263        }
6264        pipe->pipe_settings.capture.anr_gdc_binary.left_padding =
6265            pipe->pipe_settings.capture.post_isp_binary.left_padding;
6266
6267        /* Pre-gdc */
6268        {
6269                struct ia_css_binary_descr pre_gdc_descr;
6270
6271                ia_css_pipe_get_pre_gdc_binarydesc(pipe, &pre_gdc_descr, &pre_in_info,
6272                                                   &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
6273                err = ia_css_binary_find(&pre_gdc_descr,
6274                                         &pipe->pipe_settings.capture.pre_isp_binary);
6275                if (err)
6276                        return err;
6277        }
6278        pipe->pipe_settings.capture.pre_isp_binary.left_padding =
6279            pipe->pipe_settings.capture.anr_gdc_binary.left_padding;
6280
6281        /* Viewfinder post-processing */
6282        if (need_pp) {
6283                vf_pp_in_info =
6284                    &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info;
6285        } else {
6286                vf_pp_in_info =
6287                    &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info;
6288        }
6289
6290        {
6291                struct ia_css_binary_descr vf_pp_descr;
6292
6293                ia_css_pipe_get_vfpp_binarydesc(pipe,
6294                                                &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
6295                err = ia_css_binary_find(&vf_pp_descr,
6296                                         &pipe->pipe_settings.capture.vf_pp_binary);
6297                if (err)
6298                        return err;
6299        }
6300
6301        /* Copy */
6302#ifdef ISP2401
6303        /* For CSI2+, only the direct sensor mode/online requires ISP copy */
6304        need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
6305#endif
6306        if (need_isp_copy)
6307                load_copy_binary(pipe,
6308                                 &pipe->pipe_settings.capture.copy_binary,
6309                                 &pipe->pipe_settings.capture.pre_isp_binary);
6310
6311        return err;
6312}
6313
6314static int load_bayer_isp_binaries(struct ia_css_pipe *pipe)
6315{
6316        struct ia_css_frame_info pre_isp_in_info, *pipe_out_info;
6317        int err = 0;
6318        struct ia_css_binary_descr pre_de_descr;
6319
6320        IA_CSS_ENTER_PRIVATE("");
6321        assert(pipe);
6322        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6323               pipe->mode == IA_CSS_PIPE_ID_COPY);
6324        pipe_out_info = &pipe->output_info[0];
6325
6326        if (pipe->pipe_settings.capture.pre_isp_binary.info)
6327                return 0;
6328
6329        err = ia_css_frame_check_info(pipe_out_info);
6330        if (err)
6331                return err;
6332
6333        ia_css_pipe_get_pre_de_binarydesc(pipe, &pre_de_descr,
6334                                          &pre_isp_in_info,
6335                                          pipe_out_info);
6336
6337        err = ia_css_binary_find(&pre_de_descr,
6338                                 &pipe->pipe_settings.capture.pre_isp_binary);
6339
6340        return err;
6341}
6342
6343static int load_low_light_binaries(struct ia_css_pipe *pipe)
6344{
6345        struct ia_css_frame_info pre_in_info, anr_in_info,
6346                        post_in_info, post_out_info,
6347                        vf_info, *pipe_vf_out_info, *pipe_out_info,
6348                        *vf_pp_in_info;
6349        bool need_pp;
6350        bool need_isp_copy = true;
6351        int err = 0;
6352
6353        IA_CSS_ENTER_PRIVATE("");
6354        assert(pipe);
6355        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6356               pipe->mode == IA_CSS_PIPE_ID_COPY);
6357
6358        if (pipe->pipe_settings.capture.pre_isp_binary.info)
6359                return 0;
6360        pipe_vf_out_info = &pipe->vf_output_info[0];
6361        pipe_out_info = &pipe->output_info[0];
6362
6363        vf_info = *pipe_vf_out_info;
6364        err = ia_css_util_check_vf_out_info(pipe_out_info,
6365                                            &vf_info);
6366        if (err)
6367                return err;
6368        need_pp = need_capture_pp(pipe);
6369
6370        ia_css_frame_info_set_format(&vf_info,
6371                                     IA_CSS_FRAME_FORMAT_YUV_LINE);
6372
6373        /* we build up the pipeline starting at the end */
6374        /* Capture post-processing */
6375        if (need_pp) {
6376                struct ia_css_binary_descr capture_pp_descr;
6377
6378                ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
6379                                                     &post_out_info,
6380                                                     pipe_out_info, &vf_info);
6381                err = ia_css_binary_find(&capture_pp_descr,
6382                                         &pipe->pipe_settings.capture.capture_pp_binary);
6383                if (err)
6384                        return err;
6385        } else {
6386                post_out_info = *pipe_out_info;
6387        }
6388
6389        /* Post-anr */
6390        {
6391                struct ia_css_binary_descr post_anr_descr;
6392
6393                ia_css_pipe_get_post_anr_binarydesc(pipe,
6394                                                    &post_anr_descr, &post_in_info, &post_out_info, &vf_info);
6395                err = ia_css_binary_find(&post_anr_descr,
6396                                         &pipe->pipe_settings.capture.post_isp_binary);
6397                if (err)
6398                        return err;
6399        }
6400
6401        /* Anr */
6402        {
6403                struct ia_css_binary_descr anr_descr;
6404
6405                ia_css_pipe_get_anr_binarydesc(pipe, &anr_descr, &anr_in_info,
6406                                               &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
6407                err = ia_css_binary_find(&anr_descr,
6408                                         &pipe->pipe_settings.capture.anr_gdc_binary);
6409                if (err)
6410                        return err;
6411        }
6412        pipe->pipe_settings.capture.anr_gdc_binary.left_padding =
6413            pipe->pipe_settings.capture.post_isp_binary.left_padding;
6414
6415        /* Pre-anr */
6416        {
6417                struct ia_css_binary_descr pre_anr_descr;
6418
6419                ia_css_pipe_get_pre_anr_binarydesc(pipe, &pre_anr_descr, &pre_in_info,
6420                                                   &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
6421                err = ia_css_binary_find(&pre_anr_descr,
6422                                         &pipe->pipe_settings.capture.pre_isp_binary);
6423                if (err)
6424                        return err;
6425        }
6426        pipe->pipe_settings.capture.pre_isp_binary.left_padding =
6427            pipe->pipe_settings.capture.anr_gdc_binary.left_padding;
6428
6429        /* Viewfinder post-processing */
6430        if (need_pp) {
6431                vf_pp_in_info =
6432                    &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info;
6433        } else {
6434                vf_pp_in_info =
6435                    &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info;
6436        }
6437
6438        {
6439                struct ia_css_binary_descr vf_pp_descr;
6440
6441                ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
6442                                                vf_pp_in_info, pipe_vf_out_info);
6443                err = ia_css_binary_find(&vf_pp_descr,
6444                                         &pipe->pipe_settings.capture.vf_pp_binary);
6445                if (err)
6446                        return err;
6447        }
6448
6449        /* Copy */
6450#ifdef ISP2401
6451        /* For CSI2+, only the direct sensor mode/online requires ISP copy */
6452        need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
6453#endif
6454        if (need_isp_copy)
6455                err = load_copy_binary(pipe,
6456                                       &pipe->pipe_settings.capture.copy_binary,
6457                                       &pipe->pipe_settings.capture.pre_isp_binary);
6458
6459        return err;
6460}
6461
6462static bool copy_on_sp(struct ia_css_pipe *pipe)
6463{
6464        bool rval;
6465
6466        assert(pipe);
6467        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "copy_on_sp() enter:\n");
6468
6469        rval = true;
6470
6471        rval &= (pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
6472
6473        rval &= (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW);
6474
6475        rval &= ((pipe->stream->config.input_config.format ==
6476                    ATOMISP_INPUT_FORMAT_BINARY_8) ||
6477                    (pipe->config.mode == IA_CSS_PIPE_MODE_COPY));
6478
6479        return rval;
6480}
6481
6482static int load_capture_binaries(struct ia_css_pipe *pipe)
6483{
6484        int err = 0;
6485        bool must_be_raw;
6486
6487        IA_CSS_ENTER_PRIVATE("");
6488        assert(pipe);
6489        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6490               pipe->mode == IA_CSS_PIPE_ID_COPY);
6491
6492        if (pipe->pipe_settings.capture.primary_binary[0].info) {
6493                IA_CSS_LEAVE_ERR_PRIVATE(0);
6494                return 0;
6495        }
6496
6497        /* in primary, advanced,low light or bayer,
6498                                                the input format must be raw */
6499        must_be_raw =
6500            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_ADVANCED ||
6501            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER ||
6502            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT;
6503        err = ia_css_util_check_input(&pipe->stream->config, must_be_raw, false);
6504        if (err) {
6505                IA_CSS_LEAVE_ERR_PRIVATE(err);
6506                return err;
6507        }
6508        if (copy_on_sp(pipe) &&
6509            pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
6510                ia_css_frame_info_init(
6511                    &pipe->output_info[0],
6512                    JPEG_BYTES,
6513                    1,
6514                    IA_CSS_FRAME_FORMAT_BINARY_8,
6515                    0);
6516                IA_CSS_LEAVE_ERR_PRIVATE(0);
6517                return 0;
6518        }
6519
6520        switch (pipe->config.default_capture_config.mode) {
6521        case IA_CSS_CAPTURE_MODE_RAW:
6522                err = load_copy_binaries(pipe);
6523#if defined(ISP2401)
6524                if (!err)
6525                        pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online;
6526#endif
6527                break;
6528        case IA_CSS_CAPTURE_MODE_BAYER:
6529                err = load_bayer_isp_binaries(pipe);
6530                break;
6531        case IA_CSS_CAPTURE_MODE_PRIMARY:
6532                err = load_primary_binaries(pipe);
6533                break;
6534        case IA_CSS_CAPTURE_MODE_ADVANCED:
6535                err = load_advanced_binaries(pipe);
6536                break;
6537        case IA_CSS_CAPTURE_MODE_LOW_LIGHT:
6538                err = load_low_light_binaries(pipe);
6539                break;
6540        }
6541        if (err) {
6542                IA_CSS_LEAVE_ERR_PRIVATE(err);
6543                return err;
6544        }
6545
6546        IA_CSS_LEAVE_ERR_PRIVATE(err);
6547        return err;
6548}
6549
6550static int
6551unload_capture_binaries(struct ia_css_pipe *pipe)
6552{
6553        unsigned int i;
6554
6555        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
6556
6557        if (!pipe || (pipe->mode != IA_CSS_PIPE_ID_CAPTURE &&
6558                      pipe->mode != IA_CSS_PIPE_ID_COPY)) {
6559                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
6560                return -EINVAL;
6561        }
6562        ia_css_binary_unload(&pipe->pipe_settings.capture.copy_binary);
6563        for (i = 0; i < MAX_NUM_PRIMARY_STAGES; i++)
6564                ia_css_binary_unload(&pipe->pipe_settings.capture.primary_binary[i]);
6565        ia_css_binary_unload(&pipe->pipe_settings.capture.pre_isp_binary);
6566        ia_css_binary_unload(&pipe->pipe_settings.capture.anr_gdc_binary);
6567        ia_css_binary_unload(&pipe->pipe_settings.capture.post_isp_binary);
6568        ia_css_binary_unload(&pipe->pipe_settings.capture.capture_pp_binary);
6569        ia_css_binary_unload(&pipe->pipe_settings.capture.capture_ldc_binary);
6570        ia_css_binary_unload(&pipe->pipe_settings.capture.vf_pp_binary);
6571
6572        for (i = 0; i < pipe->pipe_settings.capture.num_yuv_scaler; i++)
6573                ia_css_binary_unload(&pipe->pipe_settings.capture.yuv_scaler_binary[i]);
6574
6575        kfree(pipe->pipe_settings.capture.is_output_stage);
6576        pipe->pipe_settings.capture.is_output_stage = NULL;
6577        kfree(pipe->pipe_settings.capture.yuv_scaler_binary);
6578        pipe->pipe_settings.capture.yuv_scaler_binary = NULL;
6579
6580        IA_CSS_LEAVE_ERR_PRIVATE(0);
6581        return 0;
6582}
6583
6584static bool
6585need_downscaling(const struct ia_css_resolution in_res,
6586                 const struct ia_css_resolution out_res)
6587{
6588        if (in_res.width > out_res.width || in_res.height > out_res.height)
6589                return true;
6590
6591        return false;
6592}
6593
6594static bool
6595need_yuv_scaler_stage(const struct ia_css_pipe *pipe)
6596{
6597        unsigned int i;
6598        struct ia_css_resolution in_res, out_res;
6599
6600        bool need_format_conversion = false;
6601
6602        IA_CSS_ENTER_PRIVATE("");
6603        assert(pipe);
6604        assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP);
6605
6606        /* TODO: make generic function */
6607        need_format_conversion =
6608            ((pipe->stream->config.input_config.format ==
6609                ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) &&
6610                (pipe->output_info[0].format != IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8));
6611
6612        in_res = pipe->config.input_effective_res;
6613
6614        if (pipe->config.enable_dz)
6615                return true;
6616
6617        if ((pipe->output_info[0].res.width != 0) && need_format_conversion)
6618                return true;
6619
6620        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6621                out_res = pipe->output_info[i].res;
6622
6623                /* A non-zero width means it is a valid output port */
6624                if ((out_res.width != 0) && need_downscaling(in_res, out_res))
6625                        return true;
6626        }
6627
6628        return false;
6629}
6630
6631/* TODO: it is temporarily created from ia_css_pipe_create_cas_scaler_desc */
6632/* which has some hard-coded knowledge which prevents reuse of the function. */
6633/* Later, merge this with ia_css_pipe_create_cas_scaler_desc */
6634static int ia_css_pipe_create_cas_scaler_desc_single_output(
6635            struct ia_css_frame_info *cas_scaler_in_info,
6636            struct ia_css_frame_info *cas_scaler_out_info,
6637            struct ia_css_frame_info *cas_scaler_vf_info,
6638            struct ia_css_cas_binary_descr *descr)
6639{
6640        unsigned int i;
6641        unsigned int hor_ds_factor = 0, ver_ds_factor = 0;
6642        int err = 0;
6643        struct ia_css_frame_info tmp_in_info;
6644
6645        unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP;
6646
6647        assert(cas_scaler_in_info);
6648        assert(cas_scaler_out_info);
6649
6650        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6651                            "ia_css_pipe_create_cas_scaler_desc() enter:\n");
6652
6653        /* We assume that this function is used only for single output port case. */
6654        descr->num_output_stage = 1;
6655
6656        hor_ds_factor = CEIL_DIV(cas_scaler_in_info->res.width,
6657                                 cas_scaler_out_info->res.width);
6658        ver_ds_factor = CEIL_DIV(cas_scaler_in_info->res.height,
6659                                 cas_scaler_out_info->res.height);
6660        /* use the same horizontal and vertical downscaling factor for simplicity */
6661        assert(hor_ds_factor == ver_ds_factor);
6662
6663        i = 1;
6664        while (i < hor_ds_factor) {
6665                descr->num_stage++;
6666                i *= max_scale_factor_per_stage;
6667        }
6668
6669        descr->in_info = kmalloc(descr->num_stage *
6670                                 sizeof(struct ia_css_frame_info),
6671                                 GFP_KERNEL);
6672        if (!descr->in_info) {
6673                err = -ENOMEM;
6674                goto ERR;
6675        }
6676        descr->internal_out_info = kmalloc(descr->num_stage *
6677                                           sizeof(struct ia_css_frame_info),
6678                                           GFP_KERNEL);
6679        if (!descr->internal_out_info) {
6680                err = -ENOMEM;
6681                goto ERR;
6682        }
6683        descr->out_info = kmalloc(descr->num_stage *
6684                                  sizeof(struct ia_css_frame_info),
6685                                  GFP_KERNEL);
6686        if (!descr->out_info) {
6687                err = -ENOMEM;
6688                goto ERR;
6689        }
6690        descr->vf_info = kmalloc(descr->num_stage *
6691                                 sizeof(struct ia_css_frame_info),
6692                                 GFP_KERNEL);
6693        if (!descr->vf_info) {
6694                err = -ENOMEM;
6695                goto ERR;
6696        }
6697        descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
6698                                         GFP_KERNEL);
6699        if (!descr->is_output_stage) {
6700                err = -ENOMEM;
6701                goto ERR;
6702        }
6703
6704        tmp_in_info = *cas_scaler_in_info;
6705        for (i = 0; i < descr->num_stage; i++) {
6706                descr->in_info[i] = tmp_in_info;
6707                if ((tmp_in_info.res.width / max_scale_factor_per_stage) <=
6708                    cas_scaler_out_info->res.width) {
6709                        descr->is_output_stage[i] = true;
6710                        if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) {
6711                                descr->internal_out_info[i].res.width = cas_scaler_out_info->res.width;
6712                                descr->internal_out_info[i].res.height = cas_scaler_out_info->res.height;
6713                                descr->internal_out_info[i].padded_width = cas_scaler_out_info->padded_width;
6714                                descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6715                        } else {
6716                                assert(i == (descr->num_stage - 1));
6717                                descr->internal_out_info[i].res.width = 0;
6718                                descr->internal_out_info[i].res.height = 0;
6719                        }
6720                        descr->out_info[i].res.width = cas_scaler_out_info->res.width;
6721                        descr->out_info[i].res.height = cas_scaler_out_info->res.height;
6722                        descr->out_info[i].padded_width = cas_scaler_out_info->padded_width;
6723                        descr->out_info[i].format = cas_scaler_out_info->format;
6724                        if (cas_scaler_vf_info) {
6725                                descr->vf_info[i].res.width = cas_scaler_vf_info->res.width;
6726                                descr->vf_info[i].res.height = cas_scaler_vf_info->res.height;
6727                                descr->vf_info[i].padded_width = cas_scaler_vf_info->padded_width;
6728                                ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE);
6729                        } else {
6730                                descr->vf_info[i].res.width = 0;
6731                                descr->vf_info[i].res.height = 0;
6732                                descr->vf_info[i].padded_width = 0;
6733                        }
6734                } else {
6735                        descr->is_output_stage[i] = false;
6736                        descr->internal_out_info[i].res.width = tmp_in_info.res.width /
6737                                                                max_scale_factor_per_stage;
6738                        descr->internal_out_info[i].res.height = tmp_in_info.res.height /
6739                                max_scale_factor_per_stage;
6740                        descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6741                        ia_css_frame_info_init(&descr->internal_out_info[i],
6742                                               tmp_in_info.res.width / max_scale_factor_per_stage,
6743                                               tmp_in_info.res.height / max_scale_factor_per_stage,
6744                                               IA_CSS_FRAME_FORMAT_YUV420, 0);
6745                        descr->out_info[i].res.width = 0;
6746                        descr->out_info[i].res.height = 0;
6747                        descr->vf_info[i].res.width = 0;
6748                        descr->vf_info[i].res.height = 0;
6749                }
6750                tmp_in_info = descr->internal_out_info[i];
6751        }
6752ERR:
6753        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6754                            "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n",
6755                            err);
6756        return err;
6757}
6758
6759/* FIXME: merge most of this and single output version */
6760static int
6761ia_css_pipe_create_cas_scaler_desc(struct ia_css_pipe *pipe,
6762                                   struct ia_css_cas_binary_descr *descr)
6763{
6764        struct ia_css_frame_info in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
6765        struct ia_css_frame_info *out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6766        struct ia_css_frame_info *vf_out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6767        struct ia_css_frame_info tmp_in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
6768        unsigned int i, j;
6769        unsigned int hor_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE],
6770                    ver_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE],
6771                    scale_factor = 0;
6772        unsigned int num_stages = 0;
6773        int err = 0;
6774
6775        unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP;
6776
6777        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6778                            "ia_css_pipe_create_cas_scaler_desc() enter:\n");
6779
6780        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6781                out_info[i] = NULL;
6782                vf_out_info[i] = NULL;
6783                hor_scale_factor[i] = 0;
6784                ver_scale_factor[i] = 0;
6785        }
6786
6787        in_info.res = pipe->config.input_effective_res;
6788        in_info.padded_width = in_info.res.width;
6789        descr->num_output_stage = 0;
6790        /* Find out how much scaling we need for each output */
6791        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6792                if (pipe->output_info[i].res.width != 0) {
6793                        out_info[i] = &pipe->output_info[i];
6794                        if (pipe->vf_output_info[i].res.width != 0)
6795                                vf_out_info[i] = &pipe->vf_output_info[i];
6796                        descr->num_output_stage += 1;
6797                }
6798
6799                if (out_info[i]) {
6800                        hor_scale_factor[i] = CEIL_DIV(in_info.res.width, out_info[i]->res.width);
6801                        ver_scale_factor[i] = CEIL_DIV(in_info.res.height, out_info[i]->res.height);
6802                        /* use the same horizontal and vertical scaling factor for simplicity */
6803                        assert(hor_scale_factor[i] == ver_scale_factor[i]);
6804                        scale_factor = 1;
6805                        do {
6806                                num_stages++;
6807                                scale_factor *= max_scale_factor_per_stage;
6808                        } while (scale_factor < hor_scale_factor[i]);
6809
6810                        in_info.res = out_info[i]->res;
6811                }
6812        }
6813
6814        if (need_yuv_scaler_stage(pipe) && (num_stages == 0))
6815                num_stages = 1;
6816
6817        descr->num_stage = num_stages;
6818
6819        descr->in_info = kmalloc_array(descr->num_stage,
6820                                       sizeof(struct ia_css_frame_info),
6821                                       GFP_KERNEL);
6822        if (!descr->in_info) {
6823                err = -ENOMEM;
6824                goto ERR;
6825        }
6826        descr->internal_out_info = kmalloc(descr->num_stage *
6827                                           sizeof(struct ia_css_frame_info),
6828                                           GFP_KERNEL);
6829        if (!descr->internal_out_info) {
6830                err = -ENOMEM;
6831                goto ERR;
6832        }
6833        descr->out_info = kmalloc(descr->num_stage *
6834                                  sizeof(struct ia_css_frame_info),
6835                                  GFP_KERNEL);
6836        if (!descr->out_info) {
6837                err = -ENOMEM;
6838                goto ERR;
6839        }
6840        descr->vf_info = kmalloc(descr->num_stage *
6841                                 sizeof(struct ia_css_frame_info),
6842                                 GFP_KERNEL);
6843        if (!descr->vf_info) {
6844                err = -ENOMEM;
6845                goto ERR;
6846        }
6847        descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
6848                                         GFP_KERNEL);
6849        if (!descr->is_output_stage) {
6850                err = -ENOMEM;
6851                goto ERR;
6852        }
6853
6854        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6855                if (out_info[i]) {
6856                        if (i > 0) {
6857                                assert((out_info[i - 1]->res.width >= out_info[i]->res.width) &&
6858                                       (out_info[i - 1]->res.height >= out_info[i]->res.height));
6859                        }
6860                }
6861        }
6862
6863        tmp_in_info.res = pipe->config.input_effective_res;
6864        tmp_in_info.format = IA_CSS_FRAME_FORMAT_YUV420;
6865        for (i = 0, j = 0; i < descr->num_stage; i++) {
6866                assert(j < 2);
6867                assert(out_info[j]);
6868
6869                descr->in_info[i] = tmp_in_info;
6870                if ((tmp_in_info.res.width / max_scale_factor_per_stage) <=
6871                    out_info[j]->res.width) {
6872                        descr->is_output_stage[i] = true;
6873                        if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) {
6874                                descr->internal_out_info[i].res.width = out_info[j]->res.width;
6875                                descr->internal_out_info[i].res.height = out_info[j]->res.height;
6876                                descr->internal_out_info[i].padded_width = out_info[j]->padded_width;
6877                                descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6878                        } else {
6879                                assert(i == (descr->num_stage - 1));
6880                                descr->internal_out_info[i].res.width = 0;
6881                                descr->internal_out_info[i].res.height = 0;
6882                        }
6883                        descr->out_info[i].res.width = out_info[j]->res.width;
6884                        descr->out_info[i].res.height = out_info[j]->res.height;
6885                        descr->out_info[i].padded_width = out_info[j]->padded_width;
6886                        descr->out_info[i].format = out_info[j]->format;
6887                        if (vf_out_info[j]) {
6888                                descr->vf_info[i].res.width = vf_out_info[j]->res.width;
6889                                descr->vf_info[i].res.height = vf_out_info[j]->res.height;
6890                                descr->vf_info[i].padded_width = vf_out_info[j]->padded_width;
6891                                ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE);
6892                        } else {
6893                                descr->vf_info[i].res.width = 0;
6894                                descr->vf_info[i].res.height = 0;
6895                                descr->vf_info[i].padded_width = 0;
6896                        }
6897                        j++;
6898                } else {
6899                        descr->is_output_stage[i] = false;
6900                        descr->internal_out_info[i].res.width = tmp_in_info.res.width /
6901                                                                max_scale_factor_per_stage;
6902                        descr->internal_out_info[i].res.height = tmp_in_info.res.height /
6903                                max_scale_factor_per_stage;
6904                        descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6905                        ia_css_frame_info_init(&descr->internal_out_info[i],
6906                                               tmp_in_info.res.width / max_scale_factor_per_stage,
6907                                               tmp_in_info.res.height / max_scale_factor_per_stage,
6908                                               IA_CSS_FRAME_FORMAT_YUV420, 0);
6909                        descr->out_info[i].res.width = 0;
6910                        descr->out_info[i].res.height = 0;
6911                        descr->vf_info[i].res.width = 0;
6912                        descr->vf_info[i].res.height = 0;
6913                }
6914                tmp_in_info = descr->internal_out_info[i];
6915        }
6916ERR:
6917        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6918                            "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n",
6919                            err);
6920        return err;
6921}
6922
6923static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
6924        *descr)
6925{
6926        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6927                            "ia_css_pipe_destroy_cas_scaler_desc() enter:\n");
6928        kfree(descr->in_info);
6929        descr->in_info = NULL;
6930        kfree(descr->internal_out_info);
6931        descr->internal_out_info = NULL;
6932        kfree(descr->out_info);
6933        descr->out_info = NULL;
6934        kfree(descr->vf_info);
6935        descr->vf_info = NULL;
6936        kfree(descr->is_output_stage);
6937        descr->is_output_stage = NULL;
6938        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6939                            "ia_css_pipe_destroy_cas_scaler_desc() leave\n");
6940}
6941
6942static int
6943load_yuvpp_binaries(struct ia_css_pipe *pipe)
6944{
6945        int err = 0;
6946        bool need_scaler = false;
6947        struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6948        struct ia_css_yuvpp_settings *mycs;
6949        struct ia_css_binary *next_binary;
6950        struct ia_css_cas_binary_descr cas_scaler_descr = { };
6951        unsigned int i, j;
6952        bool need_isp_copy_binary = false;
6953
6954        IA_CSS_ENTER_PRIVATE("");
6955        assert(pipe);
6956        assert(pipe->stream);
6957        assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP);
6958
6959        if (pipe->pipe_settings.yuvpp.copy_binary.info)
6960                goto ERR;
6961
6962        /* Set both must_be_raw and must_be_yuv to false then yuvpp can take rgb inputs */
6963        err = ia_css_util_check_input(&pipe->stream->config, false, false);
6964        if (err)
6965                goto ERR;
6966
6967        mycs = &pipe->pipe_settings.yuvpp;
6968
6969        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6970                if (pipe->vf_output_info[i].res.width != 0) {
6971                        err = ia_css_util_check_vf_out_info(&pipe->output_info[i],
6972                                                            &pipe->vf_output_info[i]);
6973                        if (err)
6974                                goto ERR;
6975                }
6976                vf_pp_in_info[i] = NULL;
6977        }
6978
6979        need_scaler = need_yuv_scaler_stage(pipe);
6980
6981        /* we build up the pipeline starting at the end */
6982        /* Capture post-processing */
6983        if (need_scaler) {
6984                struct ia_css_binary_descr yuv_scaler_descr;
6985
6986                err = ia_css_pipe_create_cas_scaler_desc(pipe,
6987                                                         &cas_scaler_descr);
6988                if (err)
6989                        goto ERR;
6990                mycs->num_output = cas_scaler_descr.num_output_stage;
6991                mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
6992                mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage *
6993                                                  sizeof(struct ia_css_binary),
6994                                                  GFP_KERNEL);
6995                if (!mycs->yuv_scaler_binary) {
6996                        err = -ENOMEM;
6997                        goto ERR;
6998                }
6999                mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage *
7000                                                sizeof(bool), GFP_KERNEL);
7001                if (!mycs->is_output_stage) {
7002                        err = -ENOMEM;
7003                        goto ERR;
7004                }
7005                for (i = 0; i < cas_scaler_descr.num_stage; i++) {
7006                        mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
7007                        ia_css_pipe_get_yuvscaler_binarydesc(pipe,
7008                                                             &yuv_scaler_descr,
7009                                                             &cas_scaler_descr.in_info[i],
7010                                                             &cas_scaler_descr.out_info[i],
7011                                                             &cas_scaler_descr.internal_out_info[i],
7012                                                             &cas_scaler_descr.vf_info[i]);
7013                        err = ia_css_binary_find(&yuv_scaler_descr,
7014                                                 &mycs->yuv_scaler_binary[i]);
7015                        if (err)
7016                                goto ERR;
7017                }
7018                ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
7019        } else {
7020                mycs->num_output = 1;
7021        }
7022
7023        if (need_scaler)
7024                next_binary = &mycs->yuv_scaler_binary[0];
7025        else
7026                next_binary = NULL;
7027
7028#if defined(ISP2401)
7029        /*
7030            * NOTES
7031            * - Why does the "yuvpp" pipe needs "isp_copy_binary" (i.e. ISP Copy) when
7032            *   its input is "ATOMISP_INPUT_FORMAT_YUV422_8"?
7033            *
7034            *   In most use cases, the first stage in the "yuvpp" pipe is the "yuv_scale_
7035            *   binary". However, the "yuv_scale_binary" does NOT support the input-frame
7036            *   format as "IA_CSS_STREAM _FORMAT_YUV422_8".
7037            *
7038            *   Hence, the "isp_copy_binary" is required to be present in front of the "yuv
7039            *   _scale_binary". It would translate the input-frame to the frame formats that
7040            *   are supported by the "yuv_scale_binary".
7041            *
7042            *   Please refer to "FrameWork/css/isp/pipes/capture_pp/capture_pp_1.0/capture_
7043            *   pp_defs.h" for the list of input-frame formats that are supported by the
7044            *   "yuv_scale_binary".
7045            */
7046        need_isp_copy_binary =
7047            (pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_YUV422_8);
7048#else  /* !ISP2401 */
7049        need_isp_copy_binary = true;
7050#endif /*  ISP2401 */
7051
7052        if (need_isp_copy_binary) {
7053                err = load_copy_binary(pipe,
7054                                       &mycs->copy_binary,
7055                                       next_binary);
7056
7057                if (err)
7058                        goto ERR;
7059
7060                /*
7061                    * NOTES
7062                    * - Why is "pipe->pipe_settings.capture.copy_binary.online" specified?
7063                    *
7064                    *   In some use cases, the first stage in the "yuvpp" pipe is the
7065                    *   "isp_copy_binary". The "isp_copy_binary" is designed to process
7066                    *   the input from either the system DDR or from the IPU internal VMEM.
7067                    *   So it provides the flag "online" to specify where its input is from,
7068                    *   i.e.:
7069                    *
7070                    *      (1) "online <= true", the input is from the IPU internal VMEM.
7071                    *      (2) "online <= false", the input is from the system DDR.
7072                    *
7073                    *   In other use cases, the first stage in the "yuvpp" pipe is the
7074                    *   "yuv_scale_binary". "The "yuv_scale_binary" is designed to process the
7075                    *   input ONLY from the system DDR. So it does not provide the flag "online"
7076                    *   to specify where its input is from.
7077                    */
7078                pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online;
7079        }
7080
7081        /* Viewfinder post-processing */
7082        if (need_scaler) {
7083                for (i = 0, j = 0; i < mycs->num_yuv_scaler; i++) {
7084                        if (mycs->is_output_stage[i]) {
7085                                assert(j < 2);
7086                                vf_pp_in_info[j] =
7087                                    &mycs->yuv_scaler_binary[i].vf_frame_info;
7088                                j++;
7089                        }
7090                }
7091                mycs->num_vf_pp = j;
7092        } else {
7093                vf_pp_in_info[0] =
7094                    &mycs->copy_binary.vf_frame_info;
7095                for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
7096                        vf_pp_in_info[i] = NULL;
7097
7098                mycs->num_vf_pp = 1;
7099        }
7100        mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp *
7101                                     sizeof(struct ia_css_binary),
7102                                     GFP_KERNEL);
7103        if (!mycs->vf_pp_binary) {
7104                err = -ENOMEM;
7105                goto ERR;
7106        }
7107
7108        {
7109                struct ia_css_binary_descr vf_pp_descr;
7110
7111                for (i = 0; i < mycs->num_vf_pp; i++) {
7112                        if (pipe->vf_output_info[i].res.width != 0) {
7113                                ia_css_pipe_get_vfpp_binarydesc(pipe,
7114                                                                &vf_pp_descr, vf_pp_in_info[i], &pipe->vf_output_info[i]);
7115                                err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary[i]);
7116                                if (err)
7117                                        goto ERR;
7118                        }
7119                }
7120        }
7121
7122        if (err)
7123                goto ERR;
7124
7125ERR:
7126        if (need_scaler)
7127                ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
7128
7129        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "load_yuvpp_binaries() leave, err=%d\n",
7130                            err);
7131        return err;
7132}
7133
7134static int
7135unload_yuvpp_binaries(struct ia_css_pipe *pipe)
7136{
7137        unsigned int i;
7138
7139        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7140
7141        if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
7142                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7143                return -EINVAL;
7144        }
7145        ia_css_binary_unload(&pipe->pipe_settings.yuvpp.copy_binary);
7146        for (i = 0; i < pipe->pipe_settings.yuvpp.num_yuv_scaler; i++)
7147                ia_css_binary_unload(&pipe->pipe_settings.yuvpp.yuv_scaler_binary[i]);
7148
7149        for (i = 0; i < pipe->pipe_settings.yuvpp.num_vf_pp; i++)
7150                ia_css_binary_unload(&pipe->pipe_settings.yuvpp.vf_pp_binary[i]);
7151
7152        kfree(pipe->pipe_settings.yuvpp.is_output_stage);
7153        pipe->pipe_settings.yuvpp.is_output_stage = NULL;
7154        kfree(pipe->pipe_settings.yuvpp.yuv_scaler_binary);
7155        pipe->pipe_settings.yuvpp.yuv_scaler_binary = NULL;
7156        kfree(pipe->pipe_settings.yuvpp.vf_pp_binary);
7157        pipe->pipe_settings.yuvpp.vf_pp_binary = NULL;
7158
7159        IA_CSS_LEAVE_ERR_PRIVATE(0);
7160        return 0;
7161}
7162
7163static int yuvpp_start(struct ia_css_pipe *pipe)
7164{
7165        int err = 0;
7166        enum sh_css_pipe_config_override copy_ovrd;
7167        enum ia_css_input_mode yuvpp_pipe_input_mode;
7168
7169        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7170        if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
7171                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7172                return -EINVAL;
7173        }
7174
7175        yuvpp_pipe_input_mode = pipe->stream->config.mode;
7176
7177        sh_css_metrics_start_frame();
7178
7179        /* multi stream video needs mipi buffers */
7180
7181        err = send_mipi_frames(pipe);
7182        if (err) {
7183                IA_CSS_LEAVE_ERR_PRIVATE(err);
7184                return err;
7185        }
7186
7187        {
7188                unsigned int thread_id;
7189
7190                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
7191                copy_ovrd = 1 << thread_id;
7192        }
7193
7194        start_pipe(pipe, copy_ovrd, yuvpp_pipe_input_mode);
7195
7196        IA_CSS_LEAVE_ERR_PRIVATE(err);
7197        return err;
7198}
7199
7200static int
7201sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe)
7202{
7203        int err = 0;
7204
7205        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7206
7207        if (!pipe) {
7208                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7209                return -EINVAL;
7210        }
7211        /* PIPE_MODE_COPY has no binaries, but has output frames to outside*/
7212        if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
7213                IA_CSS_LEAVE_ERR_PRIVATE(0);
7214                return 0;
7215        }
7216
7217        switch (pipe->mode) {
7218        case IA_CSS_PIPE_ID_PREVIEW:
7219                err = unload_preview_binaries(pipe);
7220                break;
7221        case IA_CSS_PIPE_ID_VIDEO:
7222                err = unload_video_binaries(pipe);
7223                break;
7224        case IA_CSS_PIPE_ID_CAPTURE:
7225                err = unload_capture_binaries(pipe);
7226                break;
7227        case IA_CSS_PIPE_ID_YUVPP:
7228                err = unload_yuvpp_binaries(pipe);
7229                break;
7230        default:
7231                break;
7232        }
7233        IA_CSS_LEAVE_ERR_PRIVATE(err);
7234        return err;
7235}
7236
7237static int
7238sh_css_pipe_load_binaries(struct ia_css_pipe *pipe)
7239{
7240        int err = 0;
7241
7242        assert(pipe);
7243        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "sh_css_pipe_load_binaries() enter:\n");
7244
7245        /* PIPE_MODE_COPY has no binaries, but has output frames to outside*/
7246        if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
7247                return err;
7248
7249        switch (pipe->mode) {
7250        case IA_CSS_PIPE_ID_PREVIEW:
7251                err = load_preview_binaries(pipe);
7252                break;
7253        case IA_CSS_PIPE_ID_VIDEO:
7254                err = load_video_binaries(pipe);
7255                break;
7256        case IA_CSS_PIPE_ID_CAPTURE:
7257                err = load_capture_binaries(pipe);
7258                break;
7259        case IA_CSS_PIPE_ID_YUVPP:
7260                err = load_yuvpp_binaries(pipe);
7261                break;
7262        case IA_CSS_PIPE_ID_ACC:
7263                break;
7264        default:
7265                err = -EINVAL;
7266                break;
7267        }
7268        if (err) {
7269                if (sh_css_pipe_unload_binaries(pipe)) {
7270                        /* currently css does not support multiple error returns in a single function,
7271                            * using -EINVAL in this case */
7272                        err = -EINVAL;
7273                }
7274        }
7275        return err;
7276}
7277
7278static int
7279create_host_yuvpp_pipeline(struct ia_css_pipe *pipe)
7280{
7281        struct ia_css_pipeline *me;
7282        int err = 0;
7283        struct ia_css_pipeline_stage *vf_pp_stage = NULL,
7284                *copy_stage = NULL,
7285                *yuv_scaler_stage = NULL;
7286        struct ia_css_binary *copy_binary,
7287                *vf_pp_binary,
7288                *yuv_scaler_binary;
7289        bool need_scaler = false;
7290        unsigned int num_stage, num_output_stage;
7291        unsigned int i, j;
7292
7293        struct ia_css_frame *in_frame = NULL;
7294        struct ia_css_frame *out_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
7295        struct ia_css_frame *bin_out_frame[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
7296        struct ia_css_frame *vf_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
7297        struct ia_css_pipeline_stage_desc stage_desc;
7298        bool need_in_frameinfo_memory = false;
7299#ifdef ISP2401
7300        bool sensor = false;
7301        bool buffered_sensor = false;
7302        bool online = false;
7303        bool continuous = false;
7304#endif
7305
7306        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7307        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
7308                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7309                return -EINVAL;
7310        }
7311        me = &pipe->pipeline;
7312        ia_css_pipeline_clean(me);
7313        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
7314                out_frame[i] = NULL;
7315                vf_frame[i] = NULL;
7316        }
7317        ia_css_pipe_util_create_output_frames(bin_out_frame);
7318        num_stage  = pipe->pipe_settings.yuvpp.num_yuv_scaler;
7319        num_output_stage   = pipe->pipe_settings.yuvpp.num_output;
7320
7321#ifdef ISP2401
7322        /* When the input system is 2401, always enable 'in_frameinfo_memory'
7323            * except for the following:
7324            * - Direct Sensor Mode Online Capture
7325            * - Direct Sensor Mode Continuous Capture
7326            * - Buffered Sensor Mode Continuous Capture
7327            */
7328        sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
7329        buffered_sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
7330        online = pipe->stream->config.online;
7331        continuous = pipe->stream->config.continuous;
7332        need_in_frameinfo_memory =
7333        !((sensor && (online || continuous)) || (buffered_sensor && continuous));
7334#else
7335        /* Construct in_frame info (only in case we have dynamic input */
7336        need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
7337#endif
7338        /* the input frame can come from:
7339            *  a) memory: connect yuvscaler to me->in_frame
7340            *  b) sensor, via copy binary: connect yuvscaler to copy binary later on */
7341        if (need_in_frameinfo_memory) {
7342                /* TODO: improve for different input formats. */
7343
7344                /*
7345                    * "pipe->stream->config.input_config.format" represents the sensor output
7346                    * frame format, e.g. YUV422 8-bit.
7347                    *
7348                    * "in_frame_format" represents the imaging pipe's input frame format, e.g.
7349                    * Bayer-Quad RAW.
7350                    */
7351                int in_frame_format;
7352
7353                if (pipe->stream->config.input_config.format ==
7354                    ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) {
7355                        in_frame_format = IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8;
7356                } else if (pipe->stream->config.input_config.format ==
7357                            ATOMISP_INPUT_FORMAT_YUV422_8) {
7358                        /*
7359                            * When the sensor output frame format is "ATOMISP_INPUT_FORMAT_YUV422_8",
7360                            * the "isp_copy_var" binary is selected as the first stage in the yuvpp
7361                            * pipe.
7362                            *
7363                            * For the "isp_copy_var" binary, it reads the YUV422-8 pixels from
7364                            * the frame buffer (at DDR) to the frame-line buffer (at VMEM).
7365                            *
7366                            * By now, the "isp_copy_var" binary does NOT provide a separated
7367                            * frame-line buffer to store the YUV422-8 pixels. Instead, it stores
7368                            * the YUV422-8 pixels in the frame-line buffer which is designed to
7369                            * store the Bayer-Quad RAW pixels.
7370                            *
7371                            * To direct the "isp_copy_var" binary reading from the RAW frame-line
7372                            * buffer, its input frame format must be specified as "IA_CSS_FRAME_
7373                            * FORMAT_RAW".
7374                            */
7375                        in_frame_format = IA_CSS_FRAME_FORMAT_RAW;
7376                } else {
7377                        in_frame_format = IA_CSS_FRAME_FORMAT_NV12;
7378                }
7379
7380                err = init_in_frameinfo_memory_defaults(pipe,
7381                                                        &me->in_frame,
7382                                                        in_frame_format);
7383
7384                if (err) {
7385                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7386                        return err;
7387                }
7388
7389                in_frame = &me->in_frame;
7390        } else {
7391                in_frame = NULL;
7392        }
7393
7394        for (i = 0; i < num_output_stage; i++) {
7395                assert(i < IA_CSS_PIPE_MAX_OUTPUT_STAGE);
7396                if (pipe->output_info[i].res.width != 0) {
7397                        err = init_out_frameinfo_defaults(pipe, &me->out_frame[i], i);
7398                        if (err) {
7399                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7400                                return err;
7401                        }
7402                        out_frame[i] = &me->out_frame[i];
7403                }
7404
7405                /* Construct vf_frame info (only in case we have VF) */
7406                if (pipe->vf_output_info[i].res.width != 0) {
7407                        err = init_vf_frameinfo_defaults(pipe, &me->vf_frame[i], i);
7408                        if (err) {
7409                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7410                                return err;
7411                        }
7412                        vf_frame[i] = &me->vf_frame[i];
7413                }
7414        }
7415
7416        copy_binary       = &pipe->pipe_settings.yuvpp.copy_binary;
7417        vf_pp_binary      = pipe->pipe_settings.yuvpp.vf_pp_binary;
7418        yuv_scaler_binary = pipe->pipe_settings.yuvpp.yuv_scaler_binary;
7419        need_scaler = need_yuv_scaler_stage(pipe);
7420
7421        if (pipe->pipe_settings.yuvpp.copy_binary.info) {
7422                struct ia_css_frame *in_frame_local = NULL;
7423
7424#ifdef ISP2401
7425                /* After isp copy is enabled in_frame needs to be passed. */
7426                if (!online)
7427                        in_frame_local = in_frame;
7428#endif
7429
7430                if (need_scaler) {
7431                        ia_css_pipe_util_set_output_frames(bin_out_frame,
7432                                                           0, NULL);
7433                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7434                                                           copy_binary,
7435                                                           bin_out_frame,
7436                                                           in_frame_local,
7437                                                           NULL);
7438                } else {
7439                        ia_css_pipe_util_set_output_frames(bin_out_frame,
7440                                                           0, out_frame[0]);
7441                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7442                                                           copy_binary,
7443                                                           bin_out_frame,
7444                                                           in_frame_local,
7445                                                           NULL);
7446                }
7447
7448                err = ia_css_pipeline_create_and_add_stage(me,
7449                                                           &stage_desc,
7450                                                           &copy_stage);
7451
7452                if (err) {
7453                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7454                        return err;
7455                }
7456
7457                if (copy_stage) {
7458                        /* if we use yuv scaler binary, vf output should be from there */
7459                        copy_stage->args.copy_vf = !need_scaler;
7460                        /* for yuvpp pipe, it should always be enabled */
7461                        copy_stage->args.copy_output = true;
7462                        /* connect output of copy binary to input of yuv scaler */
7463                        in_frame = copy_stage->args.out_frame[0];
7464                }
7465        }
7466
7467        if (need_scaler) {
7468                struct ia_css_frame *tmp_out_frame = NULL;
7469                struct ia_css_frame *tmp_vf_frame = NULL;
7470                struct ia_css_frame *tmp_in_frame = in_frame;
7471
7472                for (i = 0, j = 0; i < num_stage; i++) {
7473                        assert(j < num_output_stage);
7474                        if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
7475                                tmp_out_frame = out_frame[j];
7476                                tmp_vf_frame = vf_frame[j];
7477                        } else {
7478                                tmp_out_frame = NULL;
7479                                tmp_vf_frame = NULL;
7480                        }
7481
7482                        err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
7483                                                   tmp_out_frame,
7484                                                   NULL,
7485                                                   &yuv_scaler_binary[i],
7486                                                   &yuv_scaler_stage);
7487
7488                        if (err) {
7489                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7490                                return err;
7491                        }
7492                        /* we use output port 1 as internal output port */
7493                        tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
7494                        if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
7495                                if (tmp_vf_frame && (tmp_vf_frame->info.res.width != 0)) {
7496                                        in_frame = yuv_scaler_stage->args.out_vf_frame;
7497                                        err = add_vf_pp_stage(pipe, in_frame,
7498                                                              tmp_vf_frame,
7499                                                              &vf_pp_binary[j],
7500                                                              &vf_pp_stage);
7501
7502                                        if (err) {
7503                                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7504                                                return err;
7505                                        }
7506                                }
7507                                j++;
7508                        }
7509                }
7510        } else if (copy_stage) {
7511                if (vf_frame[0] && vf_frame[0]->info.res.width != 0) {
7512                        in_frame = copy_stage->args.out_vf_frame;
7513                        err = add_vf_pp_stage(pipe, in_frame, vf_frame[0],
7514                                              &vf_pp_binary[0], &vf_pp_stage);
7515                }
7516                if (err) {
7517                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7518                        return err;
7519                }
7520        }
7521
7522        ia_css_pipeline_finalize_stages(&pipe->pipeline,
7523                                        pipe->stream->config.continuous);
7524
7525        IA_CSS_LEAVE_ERR_PRIVATE(0);
7526
7527        return 0;
7528}
7529
7530static int
7531create_host_copy_pipeline(struct ia_css_pipe *pipe,
7532                          unsigned int max_input_width,
7533                          struct ia_css_frame *out_frame)
7534{
7535        struct ia_css_pipeline *me;
7536        int err = 0;
7537        struct ia_css_pipeline_stage_desc stage_desc;
7538
7539        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7540                            "create_host_copy_pipeline() enter:\n");
7541
7542        /* pipeline already created as part of create_host_pipeline_structure */
7543        me = &pipe->pipeline;
7544        ia_css_pipeline_clean(me);
7545
7546        /* Construct out_frame info */
7547        out_frame->contiguous = false;
7548        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
7549
7550        if (copy_on_sp(pipe) &&
7551            pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
7552                ia_css_frame_info_init(&out_frame->info, JPEG_BYTES, 1,
7553                                       IA_CSS_FRAME_FORMAT_BINARY_8, 0);
7554        } else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW) {
7555                out_frame->info.raw_bit_depth =
7556                ia_css_pipe_util_pipe_input_format_bpp(pipe);
7557        }
7558
7559        me->num_stages = 1;
7560        me->pipe_id = IA_CSS_PIPE_ID_COPY;
7561        pipe->mode  = IA_CSS_PIPE_ID_COPY;
7562
7563        ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
7564                                           IA_CSS_PIPELINE_RAW_COPY,
7565                                           max_input_width);
7566        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, NULL);
7567
7568        ia_css_pipeline_finalize_stages(&pipe->pipeline,
7569                                        pipe->stream->config.continuous);
7570
7571        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7572                            "create_host_copy_pipeline() leave:\n");
7573
7574        return err;
7575}
7576
7577static int
7578create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe)
7579{
7580        struct ia_css_pipeline *me = &pipe->pipeline;
7581        int err = 0;
7582        struct ia_css_pipeline_stage_desc stage_desc;
7583        struct ia_css_frame *out_frame = &me->out_frame[0];
7584        struct ia_css_pipeline_stage *out_stage = NULL;
7585        unsigned int thread_id;
7586        enum sh_css_queue_id queue_id;
7587        unsigned int max_input_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS;
7588
7589        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7590                            "create_host_isyscopy_capture_pipeline() enter:\n");
7591        ia_css_pipeline_clean(me);
7592
7593        /* Construct out_frame info */
7594        err = sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, 0);
7595        if (err)
7596                return err;
7597        out_frame->contiguous = false;
7598        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
7599        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
7600        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, &queue_id);
7601        out_frame->dynamic_queue_id = queue_id;
7602        out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME;
7603
7604        me->num_stages = 1;
7605        me->pipe_id = IA_CSS_PIPE_ID_CAPTURE;
7606        pipe->mode  = IA_CSS_PIPE_ID_CAPTURE;
7607        ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
7608                                           IA_CSS_PIPELINE_ISYS_COPY,
7609                                           max_input_width);
7610        err = ia_css_pipeline_create_and_add_stage(me,
7611                                                   &stage_desc, &out_stage);
7612        if (err)
7613                return err;
7614
7615        ia_css_pipeline_finalize_stages(me, pipe->stream->config.continuous);
7616
7617        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7618                            "create_host_isyscopy_capture_pipeline() leave:\n");
7619
7620        return err;
7621}
7622
7623static int
7624create_host_regular_capture_pipeline(struct ia_css_pipe *pipe)
7625{
7626        struct ia_css_pipeline *me;
7627        int err = 0;
7628        enum ia_css_capture_mode mode;
7629        struct ia_css_pipeline_stage *current_stage = NULL;
7630        struct ia_css_pipeline_stage *yuv_scaler_stage = NULL;
7631        struct ia_css_binary *copy_binary,
7632                *primary_binary[MAX_NUM_PRIMARY_STAGES],
7633                *vf_pp_binary,
7634                *pre_isp_binary,
7635                *anr_gdc_binary,
7636                *post_isp_binary,
7637                *yuv_scaler_binary,
7638                *capture_pp_binary,
7639                *capture_ldc_binary;
7640        bool need_pp = false;
7641        bool raw;
7642
7643        struct ia_css_frame *in_frame;
7644        struct ia_css_frame *out_frame;
7645        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
7646        struct ia_css_frame *vf_frame;
7647        struct ia_css_pipeline_stage_desc stage_desc;
7648        bool need_in_frameinfo_memory = false;
7649#ifdef ISP2401
7650        bool sensor = false;
7651        bool buffered_sensor = false;
7652        bool online = false;
7653        bool continuous = false;
7654#endif
7655        unsigned int i, num_yuv_scaler, num_primary_stage;
7656        bool need_yuv_pp = false;
7657        bool *is_output_stage = NULL;
7658        bool need_ldc = false;
7659
7660        IA_CSS_ENTER_PRIVATE("");
7661        assert(pipe);
7662        assert(pipe->stream);
7663        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
7664               pipe->mode == IA_CSS_PIPE_ID_COPY);
7665
7666        me = &pipe->pipeline;
7667        mode = pipe->config.default_capture_config.mode;
7668        raw = (mode == IA_CSS_CAPTURE_MODE_RAW);
7669        ia_css_pipeline_clean(me);
7670        ia_css_pipe_util_create_output_frames(out_frames);
7671
7672#ifdef ISP2401
7673        /* When the input system is 2401, always enable 'in_frameinfo_memory'
7674            * except for the following:
7675            * - Direct Sensor Mode Online Capture
7676            * - Direct Sensor Mode Online Capture
7677            * - Direct Sensor Mode Continuous Capture
7678            * - Buffered Sensor Mode Continuous Capture
7679            */
7680        sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
7681        buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
7682        online = pipe->stream->config.online;
7683        continuous = pipe->stream->config.continuous;
7684        need_in_frameinfo_memory =
7685        !((sensor && (online || continuous)) || (buffered_sensor && (online || continuous)));
7686#else
7687        /* Construct in_frame info (only in case we have dynamic input */
7688        need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
7689#endif
7690        if (need_in_frameinfo_memory) {
7691                err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
7692                                                        IA_CSS_FRAME_FORMAT_RAW);
7693                if (err) {
7694                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7695                        return err;
7696                }
7697
7698                in_frame = &me->in_frame;
7699        } else {
7700                in_frame = NULL;
7701        }
7702
7703        err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
7704        if (err) {
7705                IA_CSS_LEAVE_ERR_PRIVATE(err);
7706                return err;
7707        }
7708        out_frame = &me->out_frame[0];
7709
7710        /* Construct vf_frame info (only in case we have VF) */
7711        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
7712                if (mode == IA_CSS_CAPTURE_MODE_RAW || mode == IA_CSS_CAPTURE_MODE_BAYER) {
7713                        /* These modes don't support viewfinder output */
7714                        vf_frame = NULL;
7715                } else {
7716                        init_vf_frameinfo_defaults(pipe, &me->vf_frame[0], 0);
7717                        vf_frame = &me->vf_frame[0];
7718                }
7719        } else {
7720                vf_frame = NULL;
7721        }
7722
7723        copy_binary       = &pipe->pipe_settings.capture.copy_binary;
7724        num_primary_stage = pipe->pipe_settings.capture.num_primary_stage;
7725        if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY)) {
7726                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7727                return -EINVAL;
7728        }
7729
7730        for (i = 0; i < num_primary_stage; i++)
7731                primary_binary[i] = &pipe->pipe_settings.capture.primary_binary[i];
7732
7733        vf_pp_binary      = &pipe->pipe_settings.capture.vf_pp_binary;
7734        pre_isp_binary    = &pipe->pipe_settings.capture.pre_isp_binary;
7735        anr_gdc_binary    = &pipe->pipe_settings.capture.anr_gdc_binary;
7736        post_isp_binary   = &pipe->pipe_settings.capture.post_isp_binary;
7737        capture_pp_binary = &pipe->pipe_settings.capture.capture_pp_binary;
7738        yuv_scaler_binary = pipe->pipe_settings.capture.yuv_scaler_binary;
7739        num_yuv_scaler    = pipe->pipe_settings.capture.num_yuv_scaler;
7740        is_output_stage   = pipe->pipe_settings.capture.is_output_stage;
7741        capture_ldc_binary = &pipe->pipe_settings.capture.capture_ldc_binary;
7742
7743        need_pp = (need_capture_pp(pipe) || pipe->output_stage) &&
7744                    mode != IA_CSS_CAPTURE_MODE_RAW &&
7745                    mode != IA_CSS_CAPTURE_MODE_BAYER;
7746        need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
7747        need_ldc = (capture_ldc_binary && capture_ldc_binary->info);
7748
7749        if (pipe->pipe_settings.capture.copy_binary.info) {
7750                if (raw) {
7751                        ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7752#if defined(ISP2401)
7753                        if (!continuous) {
7754                                ia_css_pipe_get_generic_stage_desc(&stage_desc,
7755                                                                   copy_binary,
7756                                                                   out_frames,
7757                                                                   in_frame,
7758                                                                   NULL);
7759                        } else {
7760                                in_frame = pipe->stream->last_pipe->continuous_frames[0];
7761                                ia_css_pipe_get_generic_stage_desc(&stage_desc,
7762                                                                   copy_binary,
7763                                                                   out_frames,
7764                                                                   in_frame,
7765                                                                   NULL);
7766                        }
7767#else
7768                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7769                                                           copy_binary,
7770                                                           out_frames,
7771                                                           NULL, NULL);
7772#endif
7773                } else {
7774                        ia_css_pipe_util_set_output_frames(out_frames, 0,
7775                                                           in_frame);
7776                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7777                                                           copy_binary,
7778                                                           out_frames,
7779                                                           NULL, NULL);
7780                }
7781
7782                err = ia_css_pipeline_create_and_add_stage(me,
7783                                                           &stage_desc,
7784                                                           &current_stage);
7785                if (err) {
7786                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7787                        return err;
7788                }
7789        } else if (pipe->stream->config.continuous) {
7790                in_frame = pipe->stream->last_pipe->continuous_frames[0];
7791        }
7792
7793        if (mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
7794                struct ia_css_frame *local_in_frame = NULL;
7795                struct ia_css_frame *local_out_frame = NULL;
7796
7797                for (i = 0; i < num_primary_stage; i++) {
7798                        if (i == 0)
7799                                local_in_frame = in_frame;
7800                        else
7801                                local_in_frame = NULL;
7802#ifndef ISP2401
7803                        if (!need_pp && (i == num_primary_stage - 1))
7804#else
7805                        if (!need_pp && (i == num_primary_stage - 1) && !need_ldc)
7806#endif
7807                                local_out_frame = out_frame;
7808                        else
7809                                local_out_frame = NULL;
7810                        ia_css_pipe_util_set_output_frames(out_frames, 0, local_out_frame);
7811                        /*
7812                            * WARNING: The #if def flag has been added below as a
7813                            * temporary solution to solve the problem of enabling the
7814                            * view finder in a single binary in a capture flow. The
7815                            * vf-pp stage has been removed from Skycam in the solution
7816                            * provided. The vf-pp stage should be re-introduced when
7817                            * required. This  * should not be considered as a clean solution.
7818                            * Proper investigation should be done to come up with the clean
7819                            * solution.
7820                            * */
7821                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7822                                                           primary_binary[i],
7823                                                           out_frames,
7824                                                           local_in_frame,
7825                                                           NULL);
7826                        err = ia_css_pipeline_create_and_add_stage(me,
7827                                                                   &stage_desc,
7828                                                                   &current_stage);
7829                        if (err) {
7830                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7831                                return err;
7832                        }
7833                }
7834                /* If we use copy iso primary,
7835                    the input must be yuv iso raw */
7836                current_stage->args.copy_vf =
7837                    primary_binary[0]->info->sp.pipeline.mode ==
7838                    IA_CSS_BINARY_MODE_COPY;
7839                current_stage->args.copy_output = current_stage->args.copy_vf;
7840        } else if (mode == IA_CSS_CAPTURE_MODE_ADVANCED ||
7841                    mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
7842                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7843                ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
7844                                                   out_frames, in_frame, NULL);
7845                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7846                                                           NULL);
7847                if (err) {
7848                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7849                        return err;
7850                }
7851                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7852                ia_css_pipe_get_generic_stage_desc(&stage_desc, anr_gdc_binary,
7853                                                   out_frames, NULL, NULL);
7854                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7855                                                           NULL);
7856                if (err) {
7857                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7858                        return err;
7859                }
7860
7861                if (need_pp) {
7862                        ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7863                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7864                                                           post_isp_binary,
7865                                                           out_frames,
7866                                                           NULL, NULL);
7867                } else {
7868                        ia_css_pipe_util_set_output_frames(out_frames, 0,
7869                                                           out_frame);
7870                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7871                                                           post_isp_binary,
7872                                                           out_frames,
7873                                                           NULL, NULL);
7874                }
7875
7876                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7877                                                           &current_stage);
7878                if (err) {
7879                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7880                        return err;
7881                }
7882        } else if (mode == IA_CSS_CAPTURE_MODE_BAYER) {
7883                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7884                ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
7885                                                   out_frames, in_frame, NULL);
7886                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7887                                                           NULL);
7888                if (err) {
7889                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7890                        return err;
7891                }
7892        }
7893
7894#ifndef ISP2401
7895        if (need_pp && current_stage) {
7896                struct ia_css_frame *local_in_frame = NULL;
7897
7898                local_in_frame = current_stage->args.out_frame[0];
7899
7900                if (need_ldc) {
7901                        ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7902                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7903                                                           capture_ldc_binary,
7904                                                           out_frames,
7905                                                           local_in_frame,
7906                                                           NULL);
7907                        err = ia_css_pipeline_create_and_add_stage(me,
7908                                                                   &stage_desc,
7909                                                                   &current_stage);
7910                        local_in_frame = current_stage->args.out_frame[0];
7911                }
7912                err = add_capture_pp_stage(pipe, me, local_in_frame,
7913                                           need_yuv_pp ? NULL : out_frame,
7914#else
7915        /* ldc and capture_pp not supported in same pipeline */
7916        if (need_ldc && current_stage) {
7917                in_frame = current_stage->args.out_frame[0];
7918                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7919                ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_ldc_binary,
7920                                                   out_frames, in_frame, NULL);
7921                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7922                                                           NULL);
7923        } else if (need_pp && current_stage) {
7924                in_frame = current_stage->args.out_frame[0];
7925                err = add_capture_pp_stage(pipe, me, in_frame,
7926                                           need_yuv_pp ? NULL : out_frame,
7927#endif
7928                                           capture_pp_binary,
7929                                           &current_stage);
7930                if (err) {
7931                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7932                        return err;
7933                }
7934        }
7935
7936        if (need_yuv_pp && current_stage) {
7937                struct ia_css_frame *tmp_in_frame = current_stage->args.out_frame[0];
7938                struct ia_css_frame *tmp_out_frame = NULL;
7939
7940                for (i = 0; i < num_yuv_scaler; i++) {
7941                        if (is_output_stage[i])
7942                                tmp_out_frame = out_frame;
7943                        else
7944                                tmp_out_frame = NULL;
7945
7946                        err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
7947                                                   tmp_out_frame, NULL,
7948                                                   &yuv_scaler_binary[i],
7949                                                   &yuv_scaler_stage);
7950                        if (err) {
7951                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7952                                return err;
7953                        }
7954                        /* we use output port 1 as internal output port */
7955                        tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
7956                }
7957        }
7958
7959        /*
7960            * WARNING: The #if def flag has been added below as a
7961            * temporary solution to solve the problem of enabling the
7962            * view finder in a single binary in a capture flow. The vf-pp
7963            * stage has been removed from Skycam in the solution provided.
7964            * The vf-pp stage should be re-introduced when required. This
7965            * should not be considered as a clean solution. Proper
7966            * investigation should be done to come up with the clean solution.
7967            * */
7968        if (mode != IA_CSS_CAPTURE_MODE_RAW &&
7969            mode != IA_CSS_CAPTURE_MODE_BAYER &&
7970            current_stage && vf_frame) {
7971                in_frame = current_stage->args.out_vf_frame;
7972                err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
7973                                      &current_stage);
7974                if (err) {
7975                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7976                        return err;
7977                }
7978        }
7979        ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
7980
7981        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7982                            "create_host_regular_capture_pipeline() leave:\n");
7983
7984        return 0;
7985}
7986
7987static int
7988create_host_capture_pipeline(struct ia_css_pipe *pipe)
7989{
7990        int err = 0;
7991
7992        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7993
7994        if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
7995                err = create_host_isyscopy_capture_pipeline(pipe);
7996        else
7997                err = create_host_regular_capture_pipeline(pipe);
7998        if (err) {
7999                IA_CSS_LEAVE_ERR_PRIVATE(err);
8000                return err;
8001        }
8002
8003        IA_CSS_LEAVE_ERR_PRIVATE(err);
8004
8005        return err;
8006}
8007
8008static int capture_start(struct ia_css_pipe *pipe)
8009{
8010        struct ia_css_pipeline *me;
8011
8012        int err = 0;
8013        enum sh_css_pipe_config_override copy_ovrd;
8014
8015        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
8016        if (!pipe) {
8017                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8018                return -EINVAL;
8019        }
8020
8021        me = &pipe->pipeline;
8022
8023        if ((pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW   ||
8024             pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) &&
8025            (pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
8026                if (copy_on_sp(pipe)) {
8027                        err = start_copy_on_sp(pipe, &me->out_frame[0]);
8028                        IA_CSS_LEAVE_ERR_PRIVATE(err);
8029                        return err;
8030                }
8031        }
8032
8033#if !defined(ISP2401)
8034        /* old isys: need to send_mipi_frames() in all pipe modes */
8035        err = send_mipi_frames(pipe);
8036        if (err) {
8037                IA_CSS_LEAVE_ERR_PRIVATE(err);
8038                return err;
8039        }
8040#elif defined(ISP2401)
8041        if (pipe->config.mode != IA_CSS_PIPE_MODE_COPY) {
8042                err = send_mipi_frames(pipe);
8043                if (err) {
8044                        IA_CSS_LEAVE_ERR_PRIVATE(err);
8045                        return err;
8046                }
8047        }
8048
8049#endif
8050
8051        {
8052                unsigned int thread_id;
8053
8054                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
8055                copy_ovrd = 1 << thread_id;
8056        }
8057        start_pipe(pipe, copy_ovrd, pipe->stream->config.mode);
8058
8059#if !defined(ISP2401)
8060        /*
8061            * old isys: for IA_CSS_PIPE_MODE_COPY pipe, isys rx has to be configured,
8062            * which is currently done in start_binary(); but COPY pipe contains no binary,
8063            * and does not call start_binary(); so we need to configure the rx here.
8064            */
8065        if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY &&
8066            pipe->stream->reconfigure_css_rx) {
8067                ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
8068                                         pipe->stream->config.mode);
8069                pipe->stream->reconfigure_css_rx = false;
8070        }
8071#endif
8072
8073        IA_CSS_LEAVE_ERR_PRIVATE(err);
8074        return err;
8075}
8076
8077static int
8078sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
8079                                  struct ia_css_frame_info *info,
8080                                  unsigned int idx)
8081{
8082        assert(pipe);
8083        assert(info);
8084
8085        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8086                            "sh_css_pipe_get_output_frame_info() enter:\n");
8087
8088        *info = pipe->output_info[idx];
8089        if (copy_on_sp(pipe) &&
8090            pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
8091                ia_css_frame_info_init(
8092                    info,
8093                    JPEG_BYTES,
8094                    1,
8095                    IA_CSS_FRAME_FORMAT_BINARY_8,
8096                    0);
8097        } else if (info->format == IA_CSS_FRAME_FORMAT_RAW ||
8098                   info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) {
8099                info->raw_bit_depth =
8100                ia_css_pipe_util_pipe_input_format_bpp(pipe);
8101        }
8102
8103        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8104                            "sh_css_pipe_get_output_frame_info() leave:\n");
8105        return 0;
8106}
8107
8108void
8109ia_css_stream_send_input_frame(const struct ia_css_stream *stream,
8110                               const unsigned short *data,
8111                               unsigned int width,
8112                               unsigned int height)
8113{
8114        assert(stream);
8115
8116        ia_css_inputfifo_send_input_frame(
8117            data, width, height,
8118            stream->config.channel_id,
8119            stream->config.input_config.format,
8120            stream->config.pixels_per_clock == 2);
8121}
8122
8123void
8124ia_css_stream_start_input_frame(const struct ia_css_stream *stream)
8125{
8126        assert(stream);
8127
8128        ia_css_inputfifo_start_frame(
8129            stream->config.channel_id,
8130            stream->config.input_config.format,
8131            stream->config.pixels_per_clock == 2);
8132}
8133
8134void
8135ia_css_stream_send_input_line(const struct ia_css_stream *stream,
8136                              const unsigned short *data,
8137                              unsigned int width,
8138                              const unsigned short *data2,
8139                              unsigned int width2)
8140{
8141        assert(stream);
8142
8143        ia_css_inputfifo_send_line(stream->config.channel_id,
8144                                   data, width, data2, width2);
8145}
8146
8147void
8148ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream,
8149                                       enum atomisp_input_format format,
8150                                       const unsigned short *data,
8151                                       unsigned int width)
8152{
8153        assert(stream);
8154        if (!data || width == 0)
8155                return;
8156        ia_css_inputfifo_send_embedded_line(stream->config.channel_id,
8157                                            format, data, width);
8158}
8159
8160void
8161ia_css_stream_end_input_frame(const struct ia_css_stream *stream)
8162{
8163        assert(stream);
8164
8165        ia_css_inputfifo_end_frame(stream->config.channel_id);
8166}
8167
8168static void
8169append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
8170{
8171        IA_CSS_ENTER_PRIVATE("l = %p, firmware = %p", l, firmware);
8172        if (!l) {
8173                IA_CSS_ERROR("NULL fw_info");
8174                IA_CSS_LEAVE_PRIVATE("");
8175                return;
8176        }
8177        while (*l)
8178                l = &(*l)->next;
8179        *l = firmware;
8180        /*firmware->next = NULL;*/ /* when multiple acc extensions are loaded, 'next' can be not NULL */
8181        IA_CSS_LEAVE_PRIVATE("");
8182}
8183
8184static void
8185remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
8186{
8187        assert(*l);
8188        assert(firmware);
8189        (void)l;
8190        (void)firmware;
8191        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() enter:\n");
8192
8193        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() leave:\n");
8194        return; /* removing single and multiple firmware is handled in acc_unload_extension() */
8195}
8196
8197static int upload_isp_code(struct ia_css_fw_info *firmware)
8198{
8199        ia_css_ptr binary;
8200
8201        if (!firmware) {
8202                IA_CSS_ERROR("NULL input parameter");
8203                return -EINVAL;
8204        }
8205        binary = firmware->info.isp.xmem_addr;
8206
8207        if (!binary) {
8208                unsigned int size = firmware->blob.size;
8209                const unsigned char *blob;
8210                const unsigned char *binary_name;
8211
8212                binary_name =
8213                    (const unsigned char *)(IA_CSS_EXT_ISP_PROG_NAME(
8214                                                firmware));
8215                blob = binary_name +
8216                        strlen((const char *)binary_name) +
8217                        1;
8218                binary = sh_css_load_blob(blob, size);
8219                firmware->info.isp.xmem_addr = binary;
8220        }
8221
8222        if (!binary)
8223                return -ENOMEM;
8224        return 0;
8225}
8226
8227static int
8228acc_load_extension(struct ia_css_fw_info *firmware)
8229{
8230        int err;
8231        struct ia_css_fw_info *hd = firmware;
8232
8233        while (hd) {
8234                err = upload_isp_code(hd);
8235                if (err)
8236                        return err;
8237                hd = hd->next;
8238        }
8239
8240        if (!firmware)
8241                return -EINVAL;
8242        firmware->loaded = true;
8243        return 0;
8244}
8245
8246static void
8247acc_unload_extension(struct ia_css_fw_info *firmware)
8248{
8249        struct ia_css_fw_info *hd = firmware;
8250        struct ia_css_fw_info *hdn = NULL;
8251
8252        if (!firmware) /* should not happen */
8253                return;
8254        /* unload and remove multiple firmwares */
8255        while (hd) {
8256                hdn = (hd->next) ? &(*hd->next) : NULL;
8257                if (hd->info.isp.xmem_addr) {
8258                        hmm_free(hd->info.isp.xmem_addr);
8259                        hd->info.isp.xmem_addr = mmgr_NULL;
8260                }
8261                hd->isp_code = NULL;
8262                hd->next = NULL;
8263                hd = hdn;
8264        }
8265
8266        firmware->loaded = false;
8267}
8268
8269/* Load firmware for extension */
8270static int
8271ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
8272                           struct ia_css_fw_info *firmware)
8273{
8274        int err = 0;
8275
8276        IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
8277
8278        if ((!firmware) || (!pipe)) {
8279                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8280                return -EINVAL;
8281        }
8282
8283        if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT)
8284                append_firmware(&pipe->output_stage, firmware);
8285        else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER)
8286                append_firmware(&pipe->vf_stage, firmware);
8287        err = acc_load_extension(firmware);
8288
8289        IA_CSS_LEAVE_ERR_PRIVATE(err);
8290        return err;
8291}
8292
8293/* Unload firmware for extension */
8294static void
8295ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
8296                             struct ia_css_fw_info *firmware)
8297{
8298        IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
8299
8300        if ((!firmware) || (!pipe)) {
8301                IA_CSS_ERROR("NULL input parameters");
8302                IA_CSS_LEAVE_PRIVATE("");
8303                return;
8304        }
8305
8306        if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT)
8307                remove_firmware(&pipe->output_stage, firmware);
8308        else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER)
8309                remove_firmware(&pipe->vf_stage, firmware);
8310        acc_unload_extension(firmware);
8311
8312        IA_CSS_LEAVE_PRIVATE("");
8313}
8314
8315bool
8316ia_css_pipeline_uses_params(struct ia_css_pipeline *me)
8317{
8318        struct ia_css_pipeline_stage *stage;
8319
8320        assert(me);
8321
8322        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8323                            "ia_css_pipeline_uses_params() enter: me=%p\n", me);
8324
8325        for (stage = me->stages; stage; stage = stage->next)
8326                if (stage->binary_info && stage->binary_info->enable.params) {
8327                        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8328                                            "ia_css_pipeline_uses_params() leave: return_bool=true\n");
8329                        return true;
8330                }
8331        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8332                            "ia_css_pipeline_uses_params() leave: return_bool=false\n");
8333        return false;
8334}
8335
8336static int
8337sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
8338                              const void *acc_fw)
8339{
8340        struct ia_css_fw_info *fw = (struct ia_css_fw_info *)acc_fw;
8341        /* In QoS case, load_extension already called, so skipping */
8342        int     err = 0;
8343
8344        if (!fw->loaded)
8345                err = acc_load_extension(fw);
8346
8347        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8348                            "sh_css_pipeline_add_acc_stage() enter: pipeline=%p, acc_fw=%p\n",
8349                            pipeline, acc_fw);
8350
8351        if (!err) {
8352                struct ia_css_pipeline_stage_desc stage_desc;
8353
8354                ia_css_pipe_get_acc_stage_desc(&stage_desc, NULL, fw);
8355                err = ia_css_pipeline_create_and_add_stage(pipeline,
8356                                                           &stage_desc,
8357                                                           NULL);
8358        }
8359
8360        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8361                            "sh_css_pipeline_add_acc_stage() leave: return_err=%d\n", err);
8362        return err;
8363}
8364
8365/*
8366    * @brief Tag a specific frame in continuous capture.
8367    * Refer to "sh_css_internal.h" for details.
8368    */
8369int ia_css_stream_capture_frame(struct ia_css_stream *stream,
8370                                unsigned int exp_id)
8371{
8372        struct sh_css_tag_descr tag_descr;
8373        u32 encoded_tag_descr;
8374        int err;
8375
8376        assert(stream);
8377        IA_CSS_ENTER("exp_id=%d", exp_id);
8378
8379        /* Only continuous streams have a tagger */
8380        if (exp_id == 0 || !stream->config.continuous) {
8381                IA_CSS_LEAVE_ERR(-EINVAL);
8382                return -EINVAL;
8383        }
8384
8385        if (!sh_css_sp_is_running()) {
8386                /* SP is not running. The queues are not valid */
8387                IA_CSS_LEAVE_ERR(-EBUSY);
8388                return -EBUSY;
8389        }
8390
8391        /* Create the tag descriptor from the parameters */
8392        sh_css_create_tag_descr(0, 0, 0, exp_id, &tag_descr);
8393        /* Encode the tag descriptor into a 32-bit value */
8394        encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr);
8395        /* Enqueue the encoded tag to the host2sp queue.
8396            * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0
8397            * on both host and the SP side.
8398            * It is mainly because it is enough to have only one tag_cmd queue */
8399        err = ia_css_bufq_enqueue_tag_cmd(encoded_tag_descr);
8400
8401        IA_CSS_LEAVE_ERR(err);
8402        return err;
8403}
8404
8405/*
8406    * @brief Configure the continuous capture.
8407    * Refer to "sh_css_internal.h" for details.
8408    */
8409int ia_css_stream_capture(struct ia_css_stream *stream, int num_captures,
8410                          unsigned int skip, int offset)
8411{
8412        struct sh_css_tag_descr tag_descr;
8413        unsigned int encoded_tag_descr;
8414        int return_err;
8415
8416        if (!stream)
8417                return -EINVAL;
8418
8419        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8420                            "ia_css_stream_capture() enter: num_captures=%d, skip=%d, offset=%d\n",
8421                            num_captures, skip, offset);
8422
8423        /* Check if the tag descriptor is valid */
8424        if (num_captures < SH_CSS_MINIMUM_TAG_ID) {
8425                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8426                                    "ia_css_stream_capture() leave: return_err=%d\n",
8427                                    -EINVAL);
8428                return -EINVAL;
8429        }
8430
8431        /* Create the tag descriptor from the parameters */
8432        sh_css_create_tag_descr(num_captures, skip, offset, 0, &tag_descr);
8433
8434        /* Encode the tag descriptor into a 32-bit value */
8435        encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr);
8436
8437        if (!sh_css_sp_is_running()) {
8438                /* SP is not running. The queues are not valid */
8439                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8440                                    "ia_css_stream_capture() leaving:queues unavailable\n");
8441                return -EBUSY;
8442        }
8443
8444        /* Enqueue the encoded tag to the host2sp queue.
8445            * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0
8446            * on both host and the SP side.
8447            * It is mainly because it is enough to have only one tag_cmd queue */
8448        return_err = ia_css_bufq_enqueue_tag_cmd((uint32_t)encoded_tag_descr);
8449
8450        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8451                            "ia_css_stream_capture() leave: return_err=%d\n",
8452                            return_err);
8453
8454        return return_err;
8455}
8456
8457void ia_css_stream_request_flash(struct ia_css_stream *stream)
8458{
8459        (void)stream;
8460
8461        assert(stream);
8462        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8463                            "ia_css_stream_request_flash() enter: void\n");
8464
8465#ifndef ISP2401
8466        sh_css_write_host2sp_command(host2sp_cmd_start_flash);
8467#else
8468        if (sh_css_sp_is_running()) {
8469                if (!sh_css_write_host2sp_command(host2sp_cmd_start_flash)) {
8470                        IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed");
8471                        ia_css_debug_dump_sp_sw_debug_info();
8472                        ia_css_debug_dump_debug_info(NULL);
8473                }
8474        } else {
8475                IA_CSS_LOG("SP is not running!");
8476        }
8477
8478#endif
8479        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8480                            "ia_css_stream_request_flash() leave: return_void\n");
8481}
8482
8483static void
8484sh_css_init_host_sp_control_vars(void)
8485{
8486        const struct ia_css_fw_info *fw;
8487        unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started;
8488
8489        unsigned int HIVE_ADDR_host_sp_queues_initialized;
8490        unsigned int HIVE_ADDR_sp_sleep_mode;
8491        unsigned int HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb;
8492#ifndef ISP2401
8493        unsigned int HIVE_ADDR_sp_stop_copy_preview;
8494#endif
8495        unsigned int HIVE_ADDR_host_sp_com;
8496        unsigned int o = offsetof(struct host_sp_communication, host2sp_command)
8497                            / sizeof(int);
8498
8499        unsigned int i;
8500
8501        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8502                            "sh_css_init_host_sp_control_vars() enter: void\n");
8503
8504        fw = &sh_css_sp_fw;
8505        HIVE_ADDR_ia_css_ispctrl_sp_isp_started = fw->info.sp.isp_started;
8506
8507        HIVE_ADDR_host_sp_queues_initialized =
8508            fw->info.sp.host_sp_queues_initialized;
8509        HIVE_ADDR_sp_sleep_mode = fw->info.sp.sleep_mode;
8510        HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb = fw->info.sp.invalidate_tlb;
8511#ifndef ISP2401
8512        HIVE_ADDR_sp_stop_copy_preview = fw->info.sp.stop_copy_preview;
8513#endif
8514        HIVE_ADDR_host_sp_com = fw->info.sp.host_sp_com;
8515
8516        (void)HIVE_ADDR_ia_css_ispctrl_sp_isp_started; /* Suppres warnings in CRUN */
8517
8518        (void)HIVE_ADDR_sp_sleep_mode;
8519        (void)HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb;
8520#ifndef ISP2401
8521        (void)HIVE_ADDR_sp_stop_copy_preview;
8522#endif
8523        (void)HIVE_ADDR_host_sp_com;
8524
8525        sp_dmem_store_uint32(SP0_ID,
8526                             (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started),
8527                             (uint32_t)(0));
8528
8529        sp_dmem_store_uint32(SP0_ID,
8530                             (unsigned int)sp_address_of(host_sp_queues_initialized),
8531                             (uint32_t)(0));
8532        sp_dmem_store_uint32(SP0_ID,
8533                             (unsigned int)sp_address_of(sp_sleep_mode),
8534                             (uint32_t)(0));
8535        sp_dmem_store_uint32(SP0_ID,
8536                             (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb),
8537                             (uint32_t)(false));
8538#ifndef ISP2401
8539        sp_dmem_store_uint32(SP0_ID,
8540                             (unsigned int)sp_address_of(sp_stop_copy_preview),
8541                             my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0));
8542#endif
8543        store_sp_array_uint(host_sp_com, o, host2sp_cmd_ready);
8544
8545        for (i = 0; i < N_CSI_PORTS; i++) {
8546                sh_css_update_host2sp_num_mipi_frames
8547                (my_css.num_mipi_frames[i]);
8548        }
8549
8550        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8551                            "sh_css_init_host_sp_control_vars() leave: return_void\n");
8552}
8553
8554/*
8555 * create the internal structures and fill in the configuration data
8556 */
8557
8558static const struct
8559ia_css_pipe_config ia_css_pipe_default_config = DEFAULT_PIPE_CONFIG;
8560
8561void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config)
8562{
8563        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_config_defaults()\n");
8564        memcpy(pipe_config, &ia_css_pipe_default_config, sizeof(*pipe_config));
8565}
8566
8567void
8568ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config *extra_config)
8569{
8570        if (!extra_config) {
8571                IA_CSS_ERROR("NULL input parameter");
8572                return;
8573        }
8574
8575        extra_config->enable_raw_binning = false;
8576        extra_config->enable_yuv_ds = false;
8577        extra_config->enable_high_speed = false;
8578        extra_config->enable_dvs_6axis = false;
8579        extra_config->enable_reduced_pipe = false;
8580        extra_config->disable_vf_pp = false;
8581        extra_config->enable_fractional_ds = false;
8582}
8583
8584void ia_css_stream_config_defaults(struct ia_css_stream_config *stream_config)
8585{
8586        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_config_defaults()\n");
8587        assert(stream_config);
8588        memset(stream_config, 0, sizeof(*stream_config));
8589        stream_config->online = true;
8590        stream_config->left_padding = -1;
8591        stream_config->pixels_per_clock = 1;
8592        /* temporary default value for backwards compatibility.
8593            * This field used to be hardcoded within CSS but this has now
8594            * been moved to the stream_config struct. */
8595        stream_config->source.port.rxcount = 0x04040404;
8596}
8597
8598static int
8599ia_css_acc_pipe_create(struct ia_css_pipe *pipe)
8600{
8601        int err = 0;
8602
8603        if (!pipe) {
8604                IA_CSS_ERROR("NULL input parameter");
8605                return -EINVAL;
8606        }
8607
8608        /* There is not meaning for num_execs = 0 semantically. Run atleast once. */
8609        if (pipe->config.acc_num_execs == 0)
8610                pipe->config.acc_num_execs = 1;
8611
8612        if (pipe->config.acc_extension)
8613                err = ia_css_pipe_load_extension(pipe, pipe->config.acc_extension);
8614
8615        return err;
8616}
8617
8618int ia_css_pipe_create(const struct ia_css_pipe_config *config,
8619                       struct ia_css_pipe **pipe)
8620{
8621        int err = 0;
8622
8623        IA_CSS_ENTER_PRIVATE("config = %p, pipe = %p", config, pipe);
8624
8625        if (!config || !pipe) {
8626                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8627                return -EINVAL;
8628        }
8629
8630        err = ia_css_pipe_create_extra(config, NULL, pipe);
8631
8632        if (err == 0)
8633                IA_CSS_LOG("pipe created successfully = %p", *pipe);
8634
8635        IA_CSS_LEAVE_ERR_PRIVATE(err);
8636
8637        return err;
8638}
8639
8640int
8641ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
8642                         const struct ia_css_pipe_extra_config *extra_config,
8643                         struct ia_css_pipe **pipe)
8644{
8645        int err = -EINVAL;
8646        struct ia_css_pipe *internal_pipe = NULL;
8647        unsigned int i;
8648
8649        IA_CSS_ENTER_PRIVATE("config = %p, extra_config = %p and pipe = %p", config, extra_config, pipe);
8650
8651        /* do not allow to create more than the maximum limit */
8652        if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX) {
8653                IA_CSS_LEAVE_ERR_PRIVATE(-ENOSPC);
8654                return -EINVAL;
8655        }
8656
8657        if ((!pipe) || (!config)) {
8658                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8659                return -EINVAL;
8660        }
8661
8662        ia_css_debug_dump_pipe_config(config);
8663        ia_css_debug_dump_pipe_extra_config(extra_config);
8664
8665        err = create_pipe(config->mode, &internal_pipe, false);
8666        if (err) {
8667                IA_CSS_LEAVE_ERR_PRIVATE(err);
8668                return err;
8669        }
8670
8671        /* now we have a pipe structure to fill */
8672        internal_pipe->config = *config;
8673        if (extra_config)
8674                internal_pipe->extra_config = *extra_config;
8675        else
8676                ia_css_pipe_extra_config_defaults(&internal_pipe->extra_config);
8677
8678        if (config->mode == IA_CSS_PIPE_MODE_ACC) {
8679                /* Temporary hack to migrate acceleration to CSS 2.0.
8680                    * In the future the code for all pipe types should be
8681                    * unified. */
8682                *pipe = internal_pipe;
8683                if (!internal_pipe->config.acc_extension &&
8684                    internal_pipe->config.num_acc_stages ==
8685                    0) { /* if no acc binary and no standalone stage */
8686                        *pipe = NULL;
8687                        IA_CSS_LEAVE_ERR_PRIVATE(0);
8688                        return 0;
8689                }
8690                return ia_css_acc_pipe_create(internal_pipe);
8691        }
8692
8693        /* Use config value when dvs_frame_delay setting equal to 2, otherwise always 1 by default */
8694        if (internal_pipe->config.dvs_frame_delay == IA_CSS_FRAME_DELAY_2)
8695                internal_pipe->dvs_frame_delay = 2;
8696        else
8697                internal_pipe->dvs_frame_delay = 1;
8698
8699        /* we still keep enable_raw_binning for backward compatibility, for any new
8700            fractional bayer downscaling, we should use bayer_ds_out_res. if both are
8701            specified, bayer_ds_out_res will take precedence.if none is specified, we
8702            set bayer_ds_out_res equal to IF output resolution(IF may do cropping on
8703            sensor output) or use default decimation factor 1. */
8704        if (internal_pipe->extra_config.enable_raw_binning &&
8705            internal_pipe->config.bayer_ds_out_res.width) {
8706                /* fill some code here, if no code is needed, please remove it during integration */
8707        }
8708
8709        /* YUV downscaling */
8710        if ((internal_pipe->config.vf_pp_in_res.width ||
8711             internal_pipe->config.capt_pp_in_res.width)) {
8712                enum ia_css_frame_format format;
8713
8714                if (internal_pipe->config.vf_pp_in_res.width) {
8715                        format = IA_CSS_FRAME_FORMAT_YUV_LINE;
8716                        ia_css_frame_info_init(
8717                            &internal_pipe->vf_yuv_ds_input_info,
8718                            internal_pipe->config.vf_pp_in_res.width,
8719                            internal_pipe->config.vf_pp_in_res.height,
8720                            format, 0);
8721                }
8722                if (internal_pipe->config.capt_pp_in_res.width) {
8723                        format = IA_CSS_FRAME_FORMAT_YUV420;
8724                        ia_css_frame_info_init(
8725                            &internal_pipe->out_yuv_ds_input_info,
8726                            internal_pipe->config.capt_pp_in_res.width,
8727                            internal_pipe->config.capt_pp_in_res.height,
8728                            format, 0);
8729                }
8730        }
8731        if (internal_pipe->config.vf_pp_in_res.width &&
8732            internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) {
8733                ia_css_frame_info_init(
8734                    &internal_pipe->vf_yuv_ds_input_info,
8735                    internal_pipe->config.vf_pp_in_res.width,
8736                    internal_pipe->config.vf_pp_in_res.height,
8737                    IA_CSS_FRAME_FORMAT_YUV_LINE, 0);
8738        }
8739        /* handle bayer downscaling output info */
8740        if (internal_pipe->config.bayer_ds_out_res.width) {
8741                ia_css_frame_info_init(
8742                    &internal_pipe->bds_output_info,
8743                    internal_pipe->config.bayer_ds_out_res.width,
8744                    internal_pipe->config.bayer_ds_out_res.height,
8745                    IA_CSS_FRAME_FORMAT_RAW, 0);
8746        }
8747
8748        /* handle output info, assume always needed */
8749        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
8750                if (internal_pipe->config.output_info[i].res.width) {
8751                        err = sh_css_pipe_configure_output(
8752                                    internal_pipe,
8753                                    internal_pipe->config.output_info[i].res.width,
8754                                    internal_pipe->config.output_info[i].res.height,
8755                                    internal_pipe->config.output_info[i].padded_width,
8756                                    internal_pipe->config.output_info[i].format,
8757                                    i);
8758                        if (err) {
8759                                IA_CSS_LEAVE_ERR_PRIVATE(err);
8760                                kvfree(internal_pipe);
8761                                internal_pipe = NULL;
8762                                return err;
8763                        }
8764                }
8765
8766                /* handle vf output info, when configured */
8767                internal_pipe->enable_viewfinder[i] =
8768                    (internal_pipe->config.vf_output_info[i].res.width != 0);
8769                if (internal_pipe->config.vf_output_info[i].res.width) {
8770                        err = sh_css_pipe_configure_viewfinder(
8771                                    internal_pipe,
8772                                    internal_pipe->config.vf_output_info[i].res.width,
8773                                    internal_pipe->config.vf_output_info[i].res.height,
8774                                    internal_pipe->config.vf_output_info[i].padded_width,
8775                                    internal_pipe->config.vf_output_info[i].format,
8776                                    i);
8777                        if (err) {
8778                                IA_CSS_LEAVE_ERR_PRIVATE(err);
8779                                kvfree(internal_pipe);
8780                                internal_pipe = NULL;
8781                                return err;
8782                        }
8783                }
8784        }
8785        if (internal_pipe->config.acc_extension) {
8786                err = ia_css_pipe_load_extension(internal_pipe,
8787                                                 internal_pipe->config.acc_extension);
8788                if (err) {
8789                        IA_CSS_LEAVE_ERR_PRIVATE(err);
8790                        kvfree(internal_pipe);
8791                        return err;
8792                }
8793        }
8794        /* set all info to zeroes first */
8795        memset(&internal_pipe->info, 0, sizeof(internal_pipe->info));
8796
8797        /* all went well, return the pipe */
8798        *pipe = internal_pipe;
8799        IA_CSS_LEAVE_ERR_PRIVATE(0);
8800        return 0;
8801}
8802
8803int
8804ia_css_pipe_get_info(const struct ia_css_pipe *pipe,
8805                     struct ia_css_pipe_info *pipe_info)
8806{
8807        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8808                            "ia_css_pipe_get_info()\n");
8809        if (!pipe_info) {
8810                ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
8811                                    "ia_css_pipe_get_info: pipe_info cannot be NULL\n");
8812                return -EINVAL;
8813        }
8814        if (!pipe || !pipe->stream) {
8815                ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
8816                                    "ia_css_pipe_get_info: ia_css_stream_create needs to be called before ia_css_[stream/pipe]_get_info\n");
8817                return -EINVAL;
8818        }
8819        /* we succeeded return the info */
8820        *pipe_info = pipe->info;
8821        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_get_info() leave\n");
8822        return 0;
8823}
8824
8825bool ia_css_pipe_has_dvs_stats(struct ia_css_pipe_info *pipe_info)
8826{
8827        unsigned int i;
8828
8829        if (pipe_info) {
8830                for (i = 0; i < IA_CSS_DVS_STAT_NUM_OF_LEVELS; i++) {
8831                        if (pipe_info->grid_info.dvs_grid.dvs_stat_grid_info.grd_cfg[i].grd_start.enable)
8832                                return true;
8833                }
8834        }
8835
8836        return false;
8837}
8838
8839int
8840ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe,
8841                                  int pin_index,
8842                                  enum ia_css_frame_format new_format)
8843{
8844        int err = 0;
8845
8846        IA_CSS_ENTER_PRIVATE("pipe = %p, pin_index = %d, new_formats = %d", pipe, pin_index, new_format);
8847
8848        if (!pipe) {
8849                IA_CSS_ERROR("pipe is not set");
8850                err = -EINVAL;
8851                IA_CSS_LEAVE_ERR_PRIVATE(err);
8852                return err;
8853        }
8854        if (0 != pin_index && 1 != pin_index) {
8855                IA_CSS_ERROR("pin index is not valid");
8856                err = -EINVAL;
8857                IA_CSS_LEAVE_ERR_PRIVATE(err);
8858                return err;
8859        }
8860        if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY) {
8861                IA_CSS_ERROR("new format is not valid");
8862                err = -EINVAL;
8863                IA_CSS_LEAVE_ERR_PRIVATE(err);
8864                return err;
8865        } else {
8866                err = ia_css_pipe_check_format(pipe, new_format);
8867                if (!err) {
8868                        if (pin_index == 0)
8869                                pipe->output_info[0].format = new_format;
8870                        else
8871                                pipe->vf_output_info[0].format = new_format;
8872                }
8873        }
8874        IA_CSS_LEAVE_ERR_PRIVATE(err);
8875        return err;
8876}
8877
8878#if !defined(ISP2401)
8879/* Configuration of INPUT_SYSTEM_VERSION_2401 is done on SP */
8880static int
8881ia_css_stream_configure_rx(struct ia_css_stream *stream)
8882{
8883        struct ia_css_input_port *config;
8884
8885        assert(stream);
8886
8887        config = &stream->config.source.port;
8888        /* AM: this code is not reliable, especially for 2400 */
8889        if (config->num_lanes == 1)
8890                stream->csi_rx_config.mode = MONO_1L_1L_0L;
8891        else if (config->num_lanes == 2)
8892                stream->csi_rx_config.mode = MONO_2L_1L_0L;
8893        else if (config->num_lanes == 3)
8894                stream->csi_rx_config.mode = MONO_3L_1L_0L;
8895        else if (config->num_lanes == 4)
8896                stream->csi_rx_config.mode = MONO_4L_1L_0L;
8897        else if (config->num_lanes != 0)
8898                return -EINVAL;
8899
8900        if (config->port > MIPI_PORT2_ID)
8901                return -EINVAL;
8902        stream->csi_rx_config.port =
8903        ia_css_isys_port_to_mipi_port(config->port);
8904        stream->csi_rx_config.timeout    = config->timeout;
8905        stream->csi_rx_config.initcount  = 0;
8906        stream->csi_rx_config.synccount  = 0x28282828;
8907        stream->csi_rx_config.rxcount    = config->rxcount;
8908        if (config->compression.type == IA_CSS_CSI2_COMPRESSION_TYPE_NONE)
8909                stream->csi_rx_config.comp = MIPI_PREDICTOR_NONE;
8910        else
8911                /* not implemented yet, requires extension of the rx_cfg_t
8912                    * struct */
8913                return -EINVAL;
8914
8915        stream->csi_rx_config.is_two_ppc = (stream->config.pixels_per_clock == 2);
8916        stream->reconfigure_css_rx = true;
8917        return 0;
8918}
8919#endif
8920
8921static struct ia_css_pipe *
8922find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes,
8923          enum ia_css_pipe_mode mode, bool copy_pipe)
8924{
8925        unsigned int i;
8926
8927        assert(pipes);
8928        for (i = 0; i < num_pipes; i++) {
8929                assert(pipes[i]);
8930                if (pipes[i]->config.mode != mode)
8931                        continue;
8932                if (copy_pipe && pipes[i]->mode != IA_CSS_PIPE_ID_COPY)
8933                        continue;
8934                return pipes[i];
8935        }
8936        return NULL;
8937}
8938
8939static int
8940ia_css_acc_stream_create(struct ia_css_stream *stream)
8941{
8942        int i;
8943        int err = 0;
8944
8945        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
8946
8947        if (!stream) {
8948                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8949                return -EINVAL;
8950        }
8951
8952        for (i = 0;  i < stream->num_pipes; i++) {
8953                struct ia_css_pipe *pipe = stream->pipes[i];
8954
8955                if (!pipe) {
8956                        IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8957                        return -EINVAL;
8958                }
8959
8960                pipe->stream = stream;
8961        }
8962
8963        /* Map SP threads before doing anything. */
8964        err = map_sp_threads(stream, true);
8965        if (err) {
8966                IA_CSS_LEAVE_ERR_PRIVATE(err);
8967                return err;
8968        }
8969
8970        for (i = 0;  i < stream->num_pipes; i++) {
8971                struct ia_css_pipe *pipe = stream->pipes[i];
8972
8973                assert(pipe);
8974                ia_css_pipe_map_queue(pipe, true);
8975        }
8976
8977        err = create_host_pipeline_structure(stream);
8978        if (err) {
8979                IA_CSS_LEAVE_ERR_PRIVATE(err);
8980                return err;
8981        }
8982
8983        stream->started = false;
8984
8985        IA_CSS_LEAVE_ERR_PRIVATE(0);
8986
8987        return 0;
8988}
8989
8990static int
8991metadata_info_init(const struct ia_css_metadata_config *mdc,
8992                   struct ia_css_metadata_info *md)
8993{
8994        /* Either both width and height should be set or neither */
8995        if ((mdc->resolution.height > 0) ^ (mdc->resolution.width > 0))
8996                return -EINVAL;
8997
8998        md->resolution = mdc->resolution;
8999        /* We round up the stride to a multiple of the width
9000            * of the port going to DDR, this is a HW requirements (DMA). */
9001        md->stride = CEIL_MUL(mdc->resolution.width, HIVE_ISP_DDR_WORD_BYTES);
9002        md->size = mdc->resolution.height * md->stride;
9003        return 0;
9004}
9005
9006/* ISP2401 */
9007static int check_pipe_resolutions(const struct ia_css_pipe *pipe)
9008{
9009        int err = 0;
9010
9011        IA_CSS_ENTER_PRIVATE("");
9012
9013        if (!pipe || !pipe->stream) {
9014                IA_CSS_ERROR("null arguments");
9015                err = -EINVAL;
9016                goto EXIT;
9017        }
9018
9019        if (ia_css_util_check_res(pipe->config.input_effective_res.width,
9020                                  pipe->config.input_effective_res.height) != 0) {
9021                IA_CSS_ERROR("effective resolution not supported");
9022                err = -EINVAL;
9023                goto EXIT;
9024        }
9025        if (!ia_css_util_resolution_is_zero(
9026                pipe->stream->config.input_config.input_res)) {
9027                if (!ia_css_util_res_leq(pipe->config.input_effective_res,
9028                                         pipe->stream->config.input_config.input_res)) {
9029                        IA_CSS_ERROR("effective resolution is larger than input resolution");
9030                        err = -EINVAL;
9031                        goto EXIT;
9032                }
9033        }
9034        if (!ia_css_util_resolution_is_even(pipe->config.output_info[0].res)) {
9035                IA_CSS_ERROR("output resolution must be even");
9036                err = -EINVAL;
9037                goto EXIT;
9038        }
9039        if (!ia_css_util_resolution_is_even(pipe->config.vf_output_info[0].res)) {
9040                IA_CSS_ERROR("VF resolution must be even");
9041                err = -EINVAL;
9042                goto EXIT;
9043        }
9044EXIT:
9045        IA_CSS_LEAVE_ERR_PRIVATE(err);
9046        return err;
9047}
9048
9049int
9050ia_css_stream_create(const struct ia_css_stream_config *stream_config,
9051                     int num_pipes,
9052                     struct ia_css_pipe *pipes[],
9053                     struct ia_css_stream **stream)
9054{
9055        struct ia_css_pipe *curr_pipe;
9056        struct ia_css_stream *curr_stream = NULL;
9057        bool spcopyonly;
9058        bool sensor_binning_changed;
9059        int i, j;
9060        int err = -EINVAL;
9061        struct ia_css_metadata_info md_info;
9062        struct ia_css_resolution effective_res;
9063#ifdef ISP2401
9064        bool aspect_ratio_crop_enabled = false;
9065#endif
9066
9067        IA_CSS_ENTER("num_pipes=%d", num_pipes);
9068        ia_css_debug_dump_stream_config(stream_config, num_pipes);
9069
9070        /* some checks */
9071        if (num_pipes == 0 ||
9072            !stream ||
9073            !pipes) {
9074                err = -EINVAL;
9075                IA_CSS_LEAVE_ERR(err);
9076                return err;
9077        }
9078
9079#if !defined(ISP2401)
9080        /* We don't support metadata for JPEG stream, since they both use str2mem */
9081        if (stream_config->input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8 &&
9082            stream_config->metadata_config.resolution.height > 0) {
9083                err = -EINVAL;
9084                IA_CSS_LEAVE_ERR(err);
9085                return err;
9086        }
9087#endif
9088
9089#ifdef ISP2401
9090        if (stream_config->online && stream_config->pack_raw_pixels) {
9091                IA_CSS_LOG("online and pack raw is invalid on input system 2401");
9092                err = -EINVAL;
9093                IA_CSS_LEAVE_ERR(err);
9094                return err;
9095        }
9096#endif
9097
9098        ia_css_debug_pipe_graph_dump_stream_config(stream_config);
9099
9100        /* check if mipi size specified */
9101        if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
9102#ifdef ISP2401
9103                if (!stream_config->online)
9104#endif
9105                {
9106                        unsigned int port = (unsigned int)stream_config->source.port.port;
9107
9108                        if (port >= N_MIPI_PORT_ID) {
9109                                err = -EINVAL;
9110                                IA_CSS_LEAVE_ERR(err);
9111                                return err;
9112                        }
9113
9114                        if (my_css.size_mem_words != 0) {
9115                                my_css.mipi_frame_size[port] = my_css.size_mem_words;
9116                        } else if (stream_config->mipi_buffer_config.size_mem_words != 0) {
9117                                my_css.mipi_frame_size[port] = stream_config->mipi_buffer_config.size_mem_words;
9118                        } else {
9119                                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9120                                                    "ia_css_stream_create() exit: error, need to set mipi frame size.\n");
9121                                assert(stream_config->mipi_buffer_config.size_mem_words != 0);
9122                                err = -EINVAL;
9123                                IA_CSS_LEAVE_ERR(err);
9124                                return err;
9125                        }
9126
9127                        if (my_css.size_mem_words != 0) {
9128                                my_css.num_mipi_frames[port] =
9129                                    2; /* Temp change: Default for backwards compatibility. */
9130                        } else if (stream_config->mipi_buffer_config.nof_mipi_buffers != 0) {
9131                                my_css.num_mipi_frames[port] =
9132                                    stream_config->mipi_buffer_config.nof_mipi_buffers;
9133                        } else {
9134                                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9135                                                    "ia_css_stream_create() exit: error, need to set number of mipi frames.\n");
9136                                assert(stream_config->mipi_buffer_config.nof_mipi_buffers != 0);
9137                                err = -EINVAL;
9138                                IA_CSS_LEAVE_ERR(err);
9139                                return err;
9140                        }
9141                }
9142
9143        /* Currently we only supported metadata up to a certain size. */
9144        err = metadata_info_init(&stream_config->metadata_config, &md_info);
9145        if (err) {
9146                IA_CSS_LEAVE_ERR(err);
9147                return err;
9148        }
9149
9150        /* allocate the stream instance */
9151        curr_stream = kzalloc(sizeof(struct ia_css_stream), GFP_KERNEL);
9152        if (!curr_stream) {
9153                err = -ENOMEM;
9154                IA_CSS_LEAVE_ERR(err);
9155                return err;
9156        }
9157        /* default all to 0 */
9158        curr_stream->info.metadata_info = md_info;
9159
9160        /* allocate pipes */
9161        curr_stream->num_pipes = num_pipes;
9162        curr_stream->pipes = kcalloc(num_pipes, sizeof(struct ia_css_pipe *), GFP_KERNEL);
9163        if (!curr_stream->pipes) {
9164                curr_stream->num_pipes = 0;
9165                kfree(curr_stream);
9166                curr_stream = NULL;
9167                err = -ENOMEM;
9168                IA_CSS_LEAVE_ERR(err);
9169                return err;
9170        }
9171        /* store pipes */
9172        spcopyonly = (num_pipes == 1) && (pipes[0]->config.mode == IA_CSS_PIPE_MODE_COPY);
9173        for (i = 0; i < num_pipes; i++)
9174                curr_stream->pipes[i] = pipes[i];
9175        curr_stream->last_pipe = curr_stream->pipes[0];
9176        /* take over stream config */
9177        curr_stream->config = *stream_config;
9178
9179#if defined(ISP2401)
9180        if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR &&
9181            stream_config->online)
9182                curr_stream->config.online = false;
9183#endif
9184
9185#ifdef ISP2401
9186        if (curr_stream->config.online) {
9187                curr_stream->config.source.port.num_lanes =
9188                    stream_config->source.port.num_lanes;
9189                curr_stream->config.mode =  IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
9190        }
9191#endif
9192        /* in case driver doesn't configure init number of raw buffers, configure it here */
9193        if (curr_stream->config.target_num_cont_raw_buf == 0)
9194                curr_stream->config.target_num_cont_raw_buf = NUM_CONTINUOUS_FRAMES;
9195        if (curr_stream->config.init_num_cont_raw_buf == 0)
9196                curr_stream->config.init_num_cont_raw_buf = curr_stream->config.target_num_cont_raw_buf;
9197
9198        /* Enable locking & unlocking of buffers in RAW buffer pool */
9199        if (curr_stream->config.ia_css_enable_raw_buffer_locking)
9200                sh_css_sp_configure_enable_raw_pool_locking(
9201                    curr_stream->config.lock_all);
9202
9203        /* copy mode specific stuff */
9204        switch (curr_stream->config.mode) {
9205        case IA_CSS_INPUT_MODE_SENSOR:
9206        case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
9207#if !defined(ISP2401)
9208                ia_css_stream_configure_rx(curr_stream);
9209#endif
9210                break;
9211        case IA_CSS_INPUT_MODE_TPG:
9212#if !defined(ISP2401)
9213                IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d",
9214                           curr_stream->config.source.tpg.x_mask,
9215                           curr_stream->config.source.tpg.y_mask,
9216                           curr_stream->config.source.tpg.x_delta,
9217                           curr_stream->config.source.tpg.y_delta,
9218                           curr_stream->config.source.tpg.xy_mask);
9219
9220                sh_css_sp_configure_tpg(
9221                    curr_stream->config.source.tpg.x_mask,
9222                    curr_stream->config.source.tpg.y_mask,
9223                    curr_stream->config.source.tpg.x_delta,
9224                    curr_stream->config.source.tpg.y_delta,
9225                    curr_stream->config.source.tpg.xy_mask);
9226#endif
9227                break;
9228        case IA_CSS_INPUT_MODE_PRBS:
9229#if !defined(ISP2401)
9230                IA_CSS_LOG("mode prbs");
9231                sh_css_sp_configure_prbs(curr_stream->config.source.prbs.seed);
9232#endif
9233                break;
9234        case IA_CSS_INPUT_MODE_MEMORY:
9235                IA_CSS_LOG("mode memory");
9236                curr_stream->reconfigure_css_rx = false;
9237                break;
9238        default:
9239                IA_CSS_LOG("mode sensor/default");
9240        }
9241
9242#ifdef ISP2401
9243        err = aspect_ratio_crop_init(curr_stream, pipes,
9244                                     &aspect_ratio_crop_enabled);
9245        if (err) {
9246                IA_CSS_LEAVE_ERR(err);
9247                goto ERR;
9248        }
9249#endif
9250        for (i = 0; i < num_pipes; i++) {
9251                struct ia_css_resolution effective_res;
9252
9253                curr_pipe = pipes[i];
9254                /* set current stream */
9255                curr_pipe->stream = curr_stream;
9256                /* take over effective info */
9257
9258                effective_res = curr_pipe->config.input_effective_res;
9259                if (effective_res.height == 0 || effective_res.width == 0) {
9260                        effective_res = curr_pipe->stream->config.input_config.effective_res;
9261
9262#if defined(ISP2401)
9263                        /* The aspect ratio cropping is currently only
9264                            * supported on the new input system. */
9265                        if (aspect_ratio_crop_check(aspect_ratio_crop_enabled, curr_pipe)) {
9266                                struct ia_css_resolution crop_res;
9267
9268                                err = aspect_ratio_crop(curr_pipe, &crop_res);
9269                                if (!err) {
9270                                        effective_res = crop_res;
9271                                } else {
9272                                        /* in case of error fallback to default
9273                                            * effective resolution from driver. */
9274                                        IA_CSS_LOG("aspect_ratio_crop() failed with err(%d)", err);
9275                                }
9276                        }
9277#endif
9278                        curr_pipe->config.input_effective_res = effective_res;
9279                }
9280                IA_CSS_LOG("effective_res=%dx%d",
9281                           effective_res.width,
9282                           effective_res.height);
9283        }
9284
9285        if (IS_ISP2401) {
9286                for (i = 0; i < num_pipes; i++) {
9287                        if (pipes[i]->config.mode != IA_CSS_PIPE_MODE_ACC &&
9288                            pipes[i]->config.mode != IA_CSS_PIPE_MODE_COPY) {
9289                                err = check_pipe_resolutions(pipes[i]);
9290                                if (err)
9291                                        goto ERR;
9292                        }
9293                }
9294        }
9295
9296        err = ia_css_stream_isp_parameters_init(curr_stream);
9297        if (err)
9298                goto ERR;
9299        IA_CSS_LOG("isp_params_configs: %p", curr_stream->isp_params_configs);
9300
9301        if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC) {
9302                *stream = curr_stream;
9303                err = ia_css_acc_stream_create(curr_stream);
9304                goto ERR;
9305        }
9306        /* sensor binning */
9307        if (!spcopyonly) {
9308                sensor_binning_changed =
9309                    sh_css_params_set_binning_factor(curr_stream,
9310                                                     curr_stream->config.sensor_binning_factor);
9311        } else {
9312                sensor_binning_changed = false;
9313        }
9314
9315        IA_CSS_LOG("sensor_binning=%d, changed=%d",
9316                   curr_stream->config.sensor_binning_factor, sensor_binning_changed);
9317        /* loop over pipes */
9318        IA_CSS_LOG("num_pipes=%d", num_pipes);
9319        curr_stream->cont_capt = false;
9320        /* Temporary hack: we give the preview pipe a reference to the capture
9321            * pipe in continuous capture mode. */
9322        if (curr_stream->config.continuous) {
9323                /* Search for the preview pipe and create the copy pipe */
9324                struct ia_css_pipe *preview_pipe;
9325                struct ia_css_pipe *video_pipe;
9326                struct ia_css_pipe *acc_pipe;
9327                struct ia_css_pipe *capture_pipe = NULL;
9328                struct ia_css_pipe *copy_pipe = NULL;
9329
9330                if (num_pipes >= 2) {
9331                        curr_stream->cont_capt = true;
9332                        curr_stream->disable_cont_vf = curr_stream->config.disable_cont_viewfinder;
9333
9334                        if (!IS_ISP2401)
9335                                curr_stream->stop_copy_preview = my_css.stop_copy_preview;
9336                }
9337
9338                /* Create copy pipe here, since it may not be exposed to the driver */
9339                preview_pipe = find_pipe(pipes, num_pipes,
9340                                         IA_CSS_PIPE_MODE_PREVIEW, false);
9341                video_pipe = find_pipe(pipes, num_pipes,
9342                                       IA_CSS_PIPE_MODE_VIDEO, false);
9343                acc_pipe = find_pipe(pipes, num_pipes, IA_CSS_PIPE_MODE_ACC,
9344                                     false);
9345                if (acc_pipe && num_pipes == 2 && curr_stream->cont_capt)
9346                        curr_stream->cont_capt =
9347                            false; /* preview + QoS case will not need cont_capt switch */
9348                if (curr_stream->cont_capt) {
9349                        capture_pipe = find_pipe(pipes, num_pipes,
9350                                                 IA_CSS_PIPE_MODE_CAPTURE,
9351                                                 false);
9352                        if (!capture_pipe) {
9353                                err = -EINVAL;
9354                                goto ERR;
9355                        }
9356                }
9357                /* We do not support preview and video pipe at the same time */
9358                if (preview_pipe && video_pipe) {
9359                        err = -EINVAL;
9360                        goto ERR;
9361                }
9362
9363                if (preview_pipe && !preview_pipe->pipe_settings.preview.copy_pipe) {
9364                        err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, &copy_pipe, true);
9365                        if (err)
9366                                goto ERR;
9367                        ia_css_pipe_config_defaults(&copy_pipe->config);
9368                        preview_pipe->pipe_settings.preview.copy_pipe = copy_pipe;
9369                        copy_pipe->stream = curr_stream;
9370                }
9371                if (preview_pipe && curr_stream->cont_capt)
9372                        preview_pipe->pipe_settings.preview.capture_pipe = capture_pipe;
9373
9374                if (video_pipe && !video_pipe->pipe_settings.video.copy_pipe) {
9375                        err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, &copy_pipe, true);
9376                        if (err)
9377                                goto ERR;
9378                        ia_css_pipe_config_defaults(&copy_pipe->config);
9379                        video_pipe->pipe_settings.video.copy_pipe = copy_pipe;
9380                        copy_pipe->stream = curr_stream;
9381                }
9382                if (video_pipe && curr_stream->cont_capt)
9383                        video_pipe->pipe_settings.video.capture_pipe = capture_pipe;
9384
9385                if (preview_pipe && acc_pipe)
9386                        preview_pipe->pipe_settings.preview.acc_pipe = acc_pipe;
9387        }
9388        for (i = 0; i < num_pipes; i++) {
9389                curr_pipe = pipes[i];
9390                /* set current stream */
9391                curr_pipe->stream = curr_stream;
9392
9393                if (!IS_ISP2401) {
9394                        /* take over effective info */
9395
9396                        effective_res = curr_pipe->config.input_effective_res;
9397                        err = ia_css_util_check_res(
9398                                effective_res.width,
9399                                effective_res.height);
9400                        if (err)
9401                                goto ERR;
9402                }
9403                /* sensor binning per pipe */
9404                if (sensor_binning_changed)
9405                        sh_css_pipe_free_shading_table(curr_pipe);
9406        }
9407
9408        /* now pipes have been configured, info should be available */
9409        for (i = 0; i < num_pipes; i++) {
9410                struct ia_css_pipe_info *pipe_info = NULL;
9411
9412                curr_pipe = pipes[i];
9413
9414                err = sh_css_pipe_load_binaries(curr_pipe);
9415                if (err)
9416                        goto ERR;
9417
9418                /* handle each pipe */
9419                pipe_info = &curr_pipe->info;
9420                for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) {
9421                        err = sh_css_pipe_get_output_frame_info(curr_pipe,
9422                                                                &pipe_info->output_info[j], j);
9423                        if (err)
9424                                goto ERR;
9425                }
9426
9427                if (IS_ISP2401)
9428                        pipe_info->output_system_in_res_info = curr_pipe->config.output_system_in_res;
9429
9430                if (!spcopyonly) {
9431                        if (!IS_ISP2401)
9432                                err = sh_css_pipe_get_shading_info(curr_pipe,
9433                                                                   &pipe_info->shading_info,
9434                                                                   NULL);
9435                        else
9436                                err = sh_css_pipe_get_shading_info(curr_pipe,
9437                                                                   &pipe_info->shading_info,
9438                                                                   &curr_pipe->config);
9439
9440                        if (err)
9441                                goto ERR;
9442                        err = sh_css_pipe_get_grid_info(curr_pipe,
9443                                                        &pipe_info->grid_info);
9444                        if (err)
9445                                goto ERR;
9446                        for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) {
9447                                sh_css_pipe_get_viewfinder_frame_info(curr_pipe,
9448                                                                      &pipe_info->vf_output_info[j],
9449                                                                      j);
9450                                if (err)
9451                                        goto ERR;
9452                        }
9453                }
9454
9455                my_css.active_pipes[ia_css_pipe_get_pipe_num(curr_pipe)] = curr_pipe;
9456        }
9457
9458        curr_stream->started = false;
9459
9460        /* Map SP threads before doing anything. */
9461        err = map_sp_threads(curr_stream, true);
9462        if (err) {
9463                IA_CSS_LOG("map_sp_threads: return_err=%d", err);
9464                goto ERR;
9465        }
9466
9467        for (i = 0; i < num_pipes; i++) {
9468                curr_pipe = pipes[i];
9469                ia_css_pipe_map_queue(curr_pipe, true);
9470        }
9471
9472        /* Create host side pipeline objects without stages */
9473        err = create_host_pipeline_structure(curr_stream);
9474        if (err) {
9475                IA_CSS_LOG("create_host_pipeline_structure: return_err=%d", err);
9476                goto ERR;
9477        }
9478
9479        /* assign curr_stream */
9480        *stream = curr_stream;
9481
9482ERR:
9483        if (!err) {
9484                /* working mode: enter into the seed list */
9485                if (my_css_save.mode == sh_css_mode_working) {
9486                        for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
9487                                if (!my_css_save.stream_seeds[i].stream) {
9488                                        IA_CSS_LOG("entered stream into loc=%d", i);
9489                                        my_css_save.stream_seeds[i].orig_stream = stream;
9490                                        my_css_save.stream_seeds[i].stream = curr_stream;
9491                                        my_css_save.stream_seeds[i].num_pipes = num_pipes;
9492                                        my_css_save.stream_seeds[i].stream_config = *stream_config;
9493                                        for (j = 0; j < num_pipes; j++) {
9494                                                my_css_save.stream_seeds[i].pipe_config[j] = pipes[j]->config;
9495                                                my_css_save.stream_seeds[i].pipes[j] = pipes[j];
9496                                                my_css_save.stream_seeds[i].orig_pipes[j] = &pipes[j];
9497                                        }
9498                                        break;
9499                                }
9500                        }
9501                } else {
9502                        ia_css_stream_destroy(curr_stream);
9503                }
9504        } else {
9505                ia_css_stream_destroy(curr_stream);
9506        }
9507        IA_CSS_LEAVE("return_err=%d mode=%d", err, my_css_save.mode);
9508        return err;
9509}
9510
9511int
9512ia_css_stream_destroy(struct ia_css_stream *stream)
9513{
9514        int i;
9515        int err = 0;
9516
9517        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
9518        if (!stream) {
9519                err = -EINVAL;
9520                IA_CSS_LEAVE_ERR_PRIVATE(err);
9521                return err;
9522        }
9523
9524        ia_css_stream_isp_parameters_uninit(stream);
9525
9526        if ((stream->last_pipe) &&
9527            ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) {
9528#if defined(ISP2401)
9529                bool free_mpi;
9530
9531                for (i = 0; i < stream->num_pipes; i++) {
9532                        struct ia_css_pipe *entry = stream->pipes[i];
9533                        unsigned int sp_thread_id;
9534                        struct sh_css_sp_pipeline_terminal *sp_pipeline_input_terminal;
9535
9536                        assert(entry);
9537                        if (entry) {
9538                                /* get the SP thread id */
9539                                if (!ia_css_pipeline_get_sp_thread_id(
9540                                        ia_css_pipe_get_pipe_num(entry), &sp_thread_id))
9541                                        return -EINVAL;
9542                                /* get the target input terminal */
9543                                sp_pipeline_input_terminal =
9544                                &sh_css_sp_group.pipe_io[sp_thread_id].input;
9545
9546                                for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) {
9547                                        ia_css_isys_stream_h isys_stream =
9548                                        &sp_pipeline_input_terminal->context.virtual_input_system_stream[i];
9549                                        if (stream->config.isys_config[i].valid && isys_stream->valid)
9550                                                ia_css_isys_stream_destroy(isys_stream);
9551                                }
9552                        }
9553                }
9554                free_mpi = stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
9555                if (IS_ISP2401) {
9556                        free_mpi |= stream->config.mode == IA_CSS_INPUT_MODE_TPG;
9557                        free_mpi |= stream->config.mode == IA_CSS_INPUT_MODE_PRBS;
9558                }
9559
9560                if (free_mpi) {
9561                        for (i = 0; i < stream->num_pipes; i++) {
9562                                struct ia_css_pipe *entry = stream->pipes[i];
9563                                /* free any mipi frames that are remaining:
9564                                    * some test stream create-destroy cycles do not generate output frames
9565                                    * and the mipi buffer is not freed in the deque function
9566                                    */
9567                                if (entry)
9568                                        free_mipi_frames(entry);
9569                        }
9570                }
9571                stream_unregister_with_csi_rx(stream);
9572#endif
9573
9574                for (i = 0; i < stream->num_pipes; i++) {
9575                        struct ia_css_pipe *curr_pipe = stream->pipes[i];
9576
9577                        assert(curr_pipe);
9578                        ia_css_pipe_map_queue(curr_pipe, false);
9579                }
9580
9581                err = map_sp_threads(stream, false);
9582                if (err) {
9583                        IA_CSS_LEAVE_ERR_PRIVATE(err);
9584                        return err;
9585                }
9586        }
9587
9588        /* remove references from pipes to stream */
9589        for (i = 0; i < stream->num_pipes; i++) {
9590                struct ia_css_pipe *entry = stream->pipes[i];
9591
9592                assert(entry);
9593                if (entry) {
9594                        /* clear reference to stream */
9595                        entry->stream = NULL;
9596                        /* check internal copy pipe */
9597                        if (entry->mode == IA_CSS_PIPE_ID_PREVIEW &&
9598                            entry->pipe_settings.preview.copy_pipe) {
9599                                IA_CSS_LOG("clearing stream on internal preview copy pipe");
9600                                entry->pipe_settings.preview.copy_pipe->stream = NULL;
9601                        }
9602                        if (entry->mode == IA_CSS_PIPE_ID_VIDEO &&
9603                            entry->pipe_settings.video.copy_pipe) {
9604                                IA_CSS_LOG("clearing stream on internal video copy pipe");
9605                                entry->pipe_settings.video.copy_pipe->stream = NULL;
9606                        }
9607                        err = sh_css_pipe_unload_binaries(entry);
9608                }
9609        }
9610        /* free associated memory of stream struct */
9611        kfree(stream->pipes);
9612        stream->pipes = NULL;
9613        stream->num_pipes = 0;
9614
9615        /* working mode: take out of the seed list */
9616        if (my_css_save.mode == sh_css_mode_working) {
9617                for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
9618                        if (my_css_save.stream_seeds[i].stream == stream) {
9619                                IA_CSS_LOG("took out stream %d", i);
9620                                my_css_save.stream_seeds[i].stream = NULL;
9621                                break;
9622                        }
9623                }
9624        }
9625
9626        kfree(stream);
9627        IA_CSS_LEAVE_ERR(err);
9628
9629        return err;
9630}
9631
9632int
9633ia_css_stream_get_info(const struct ia_css_stream *stream,
9634                       struct ia_css_stream_info *stream_info)
9635{
9636        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_info: enter/exit\n");
9637        assert(stream);
9638        assert(stream_info);
9639
9640        *stream_info = stream->info;
9641        return 0;
9642}
9643
9644/*
9645    * Rebuild a stream, including allocating structs, setting configuration and
9646    * building the required pipes.
9647    * The data is taken from the css_save struct updated upon stream creation.
9648    * The stream handle is used to identify the correct entry in the css_save struct
9649    */
9650int
9651ia_css_stream_load(struct ia_css_stream *stream)
9652{
9653        int i, j, err;
9654
9655        if (IS_ISP2401) {
9656                /* TODO remove function - DEPRECATED */
9657                (void)stream;
9658                return -ENOTSUPP;
9659        }
9660
9661        assert(stream);
9662        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() enter,\n");
9663        for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
9664                if (my_css_save.stream_seeds[i].stream != stream)
9665                        continue;
9666
9667                for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) {
9668                        int k;
9669
9670                        err = ia_css_pipe_create(&my_css_save.stream_seeds[i].pipe_config[j],
9671                                                 &my_css_save.stream_seeds[i].pipes[j]);
9672                        if (!err)
9673                                continue;
9674
9675                        for (k = 0; k < j; k++)
9676                                ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[k]);
9677                        return err;
9678                }
9679                err = ia_css_stream_create(&my_css_save.stream_seeds[i].stream_config,
9680                                           my_css_save.stream_seeds[i].num_pipes,
9681                                           my_css_save.stream_seeds[i].pipes,
9682                                           &my_css_save.stream_seeds[i].stream);
9683                if (!err)
9684                        break;
9685
9686                ia_css_stream_destroy(stream);
9687                for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
9688                        ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
9689                return err;
9690        }
9691
9692        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() exit,\n");
9693        return 0;
9694}
9695
9696int
9697ia_css_stream_start(struct ia_css_stream *stream)
9698{
9699        int err = 0;
9700
9701        IA_CSS_ENTER("stream = %p", stream);
9702        if ((!stream) || (!stream->last_pipe)) {
9703                IA_CSS_LEAVE_ERR(-EINVAL);
9704                return -EINVAL;
9705        }
9706        IA_CSS_LOG("starting %d", stream->last_pipe->mode);
9707
9708        sh_css_sp_set_disable_continuous_viewfinder(stream->disable_cont_vf);
9709
9710        /* Create host side pipeline. */
9711        err = create_host_pipeline(stream);
9712        if (err) {
9713                IA_CSS_LEAVE_ERR(err);
9714                return err;
9715        }
9716
9717#if defined(ISP2401)
9718        if ((stream->config.mode == IA_CSS_INPUT_MODE_SENSOR) ||
9719            (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR))
9720                stream_register_with_csi_rx(stream);
9721#endif
9722
9723#if !defined(ISP2401)
9724        /* Initialize mipi size checks */
9725        if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
9726                unsigned int idx;
9727                unsigned int port = (unsigned int)(stream->config.source.port.port);
9728
9729                for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) {
9730                        sh_css_sp_group.config.mipi_sizes_for_check[port][idx] =
9731                        sh_css_get_mipi_sizes_for_check(port, idx);
9732                }
9733        }
9734#endif
9735
9736        if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) {
9737                err = sh_css_config_input_network(stream);
9738                if (err)
9739                        return err;
9740        }
9741
9742        err = sh_css_pipe_start(stream);
9743        IA_CSS_LEAVE_ERR(err);
9744        return err;
9745}
9746
9747int
9748ia_css_stream_stop(struct ia_css_stream *stream)
9749{
9750        int err = 0;
9751
9752        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop() enter/exit\n");
9753        assert(stream);
9754        assert(stream->last_pipe);
9755        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop: stopping %d\n",
9756                            stream->last_pipe->mode);
9757
9758#if !defined(ISP2401)
9759        /* De-initialize mipi size checks */
9760        if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
9761                unsigned int idx;
9762                unsigned int port = (unsigned int)(stream->config.source.port.port);
9763
9764                for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++)
9765                        sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 0;
9766        }
9767#endif
9768
9769        if (!IS_ISP2401)
9770                err = ia_css_pipeline_request_stop(&stream->last_pipe->pipeline);
9771        else
9772                err = sh_css_pipes_stop(stream);
9773
9774        if (err)
9775                return err;
9776
9777        /* Ideally, unmapping should happen after pipeline_stop, but current
9778            * semantics do not allow that. */
9779        /* err = map_sp_threads(stream, false); */
9780
9781        return err;
9782}
9783
9784bool
9785ia_css_stream_has_stopped(struct ia_css_stream *stream)
9786{
9787        bool stopped;
9788
9789        assert(stream);
9790
9791        if (!IS_ISP2401)
9792                stopped = ia_css_pipeline_has_stopped(&stream->last_pipe->pipeline);
9793        else
9794                stopped = sh_css_pipes_have_stopped(stream);
9795
9796        return stopped;
9797}
9798
9799/* ISP2400 */
9800/*
9801    * Destroy the stream and all the pipes related to it.
9802    * The stream handle is used to identify the correct entry in the css_save struct
9803    */
9804int
9805ia_css_stream_unload(struct ia_css_stream *stream)
9806{
9807        int i;
9808
9809        assert(stream);
9810        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_unload() enter,\n");
9811        /* some checks */
9812        assert(stream);
9813        for (i = 0; i < MAX_ACTIVE_STREAMS; i++)
9814                if (my_css_save.stream_seeds[i].stream == stream) {
9815                        int j;
9816
9817                        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9818                                            "ia_css_stream_unload(): unloading %d (%p)\n", i,
9819                                            my_css_save.stream_seeds[i].stream);
9820                        ia_css_stream_destroy(stream);
9821                        for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
9822                                ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
9823                        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9824                                            "ia_css_stream_unload(): after unloading %d (%p)\n", i,
9825                                            my_css_save.stream_seeds[i].stream);
9826                        break;
9827                }
9828        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_unload() exit,\n");
9829        return 0;
9830}
9831
9832int
9833ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe,
9834                            enum ia_css_pipe_id *pipe_id)
9835{
9836        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_temp_pipe_to_pipe_id() enter/exit\n");
9837        if (pipe)
9838                *pipe_id = pipe->mode;
9839        else
9840                *pipe_id = IA_CSS_PIPE_ID_COPY;
9841
9842        return 0;
9843}
9844
9845enum atomisp_input_format
9846ia_css_stream_get_format(const struct ia_css_stream *stream)
9847{
9848        return stream->config.input_config.format;
9849}
9850
9851bool
9852ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream)
9853{
9854        return (stream->config.pixels_per_clock == 2);
9855}
9856
9857struct ia_css_binary *
9858ia_css_stream_get_shading_correction_binary(const struct ia_css_stream
9859        *stream)
9860{
9861        struct ia_css_pipe *pipe;
9862
9863        assert(stream);
9864
9865        pipe = stream->pipes[0];
9866
9867        if (stream->num_pipes == 2) {
9868                assert(stream->pipes[1]);
9869                if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO ||
9870                    stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
9871                        pipe = stream->pipes[1];
9872        }
9873
9874        return ia_css_pipe_get_shading_correction_binary(pipe);
9875}
9876
9877struct ia_css_binary *
9878ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream)
9879{
9880        int i;
9881        struct ia_css_pipe *video_pipe = NULL;
9882
9883        /* First we find the video pipe */
9884        for (i = 0; i < stream->num_pipes; i++) {
9885                struct ia_css_pipe *pipe = stream->pipes[i];
9886
9887                if (pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) {
9888                        video_pipe = pipe;
9889                        break;
9890                }
9891        }
9892        if (video_pipe)
9893                return &video_pipe->pipe_settings.video.video_binary;
9894        return NULL;
9895}
9896
9897struct ia_css_binary *
9898ia_css_stream_get_3a_binary(const struct ia_css_stream *stream)
9899{
9900        struct ia_css_pipe *pipe;
9901        struct ia_css_binary *s3a_binary = NULL;
9902
9903        assert(stream);
9904
9905        pipe = stream->pipes[0];
9906
9907        if (stream->num_pipes == 2) {
9908                assert(stream->pipes[1]);
9909                if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO ||
9910                    stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
9911                        pipe = stream->pipes[1];
9912        }
9913
9914        s3a_binary = ia_css_pipe_get_s3a_binary(pipe);
9915
9916        return s3a_binary;
9917}
9918
9919int
9920ia_css_stream_set_output_padded_width(struct ia_css_stream *stream,
9921                                      unsigned int output_padded_width)
9922{
9923        struct ia_css_pipe *pipe;
9924
9925        assert(stream);
9926
9927        pipe = stream->last_pipe;
9928
9929        assert(pipe);
9930
9931        /* set the config also just in case (redundant info? why do we save config in pipe?) */
9932        pipe->config.output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width;
9933        pipe->output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width;
9934
9935        return 0;
9936}
9937
9938static struct ia_css_binary *
9939ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe)
9940{
9941        struct ia_css_binary *binary = NULL;
9942
9943        assert(pipe);
9944
9945        switch (pipe->config.mode) {
9946        case IA_CSS_PIPE_MODE_PREVIEW:
9947                binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary;
9948                break;
9949        case IA_CSS_PIPE_MODE_VIDEO:
9950                binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
9951                break;
9952        case IA_CSS_PIPE_MODE_CAPTURE:
9953                if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
9954                        unsigned int i;
9955
9956                        for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
9957                                if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.sc) {
9958                                        binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i];
9959                                        break;
9960                                }
9961                        }
9962                } else if (pipe->config.default_capture_config.mode ==
9963                            IA_CSS_CAPTURE_MODE_BAYER)
9964                        binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
9965                else if (pipe->config.default_capture_config.mode ==
9966                            IA_CSS_CAPTURE_MODE_ADVANCED ||
9967                            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
9968                        if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1)
9969                                binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
9970                        else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2)
9971                                binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary;
9972                }
9973                break;
9974        default:
9975                break;
9976        }
9977
9978        if (binary && binary->info->sp.enable.sc)
9979                return binary;
9980
9981        return NULL;
9982}
9983
9984static struct ia_css_binary *
9985ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe)
9986{
9987        struct ia_css_binary *binary = NULL;
9988
9989        assert(pipe);
9990
9991        switch (pipe->config.mode) {
9992        case IA_CSS_PIPE_MODE_PREVIEW:
9993                binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary;
9994                break;
9995        case IA_CSS_PIPE_MODE_VIDEO:
9996                binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
9997                break;
9998        case IA_CSS_PIPE_MODE_CAPTURE:
9999                if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
10000                        unsigned int i;
10001
10002                        for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
10003                                if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) {
10004                                        binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i];
10005                                        break;
10006                                }
10007                        }
10008                } else if (pipe->config.default_capture_config.mode ==
10009                            IA_CSS_CAPTURE_MODE_BAYER) {
10010                        binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
10011                } else if (pipe->config.default_capture_config.mode ==
10012                            IA_CSS_CAPTURE_MODE_ADVANCED ||
10013                            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
10014                        if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1)
10015                                binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
10016                        else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2)
10017                                binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary;
10018                        else
10019                                assert(0);
10020                }
10021                break;
10022        default:
10023                break;
10024        }
10025
10026        if (binary && !binary->info->sp.enable.s3a)
10027                binary = NULL;
10028
10029        return binary;
10030}
10031
10032static struct ia_css_binary *
10033ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe)
10034{
10035        struct ia_css_binary *binary = NULL;
10036
10037        assert(pipe);
10038
10039        switch (pipe->config.mode) {
10040        case IA_CSS_PIPE_MODE_VIDEO:
10041                binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
10042                break;
10043        default:
10044                break;
10045        }
10046
10047        if (binary && !binary->info->sp.enable.dis)
10048                binary = NULL;
10049
10050        return binary;
10051}
10052
10053struct ia_css_pipeline *
10054ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe)
10055{
10056        assert(pipe);
10057
10058        return (struct ia_css_pipeline *)&pipe->pipeline;
10059}
10060
10061unsigned int
10062ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe)
10063{
10064        assert(pipe);
10065
10066        /* KW was not sure this function was not returning a value
10067            that was out of range; so added an assert, and, for the
10068            case when asserts are not enabled, clip to the largest
10069            value; pipe_num is unsigned so the value cannot be too small
10070        */
10071        assert(pipe->pipe_num < IA_CSS_PIPELINE_NUM_MAX);
10072
10073        if (pipe->pipe_num >= IA_CSS_PIPELINE_NUM_MAX)
10074                return (IA_CSS_PIPELINE_NUM_MAX - 1);
10075
10076        return pipe->pipe_num;
10077}
10078
10079unsigned int
10080ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe)
10081{
10082        assert(pipe);
10083
10084        return (unsigned int)pipe->config.isp_pipe_version;
10085}
10086
10087#define SP_START_TIMEOUT_US 30000000
10088
10089int
10090ia_css_start_sp(void)
10091{
10092        unsigned long timeout;
10093        int err = 0;
10094
10095        IA_CSS_ENTER("");
10096        sh_css_sp_start_isp();
10097
10098        /* waiting for the SP is completely started */
10099        timeout = SP_START_TIMEOUT_US;
10100        while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout) {
10101                timeout--;
10102                udelay(1);
10103        }
10104        if (timeout == 0) {
10105                IA_CSS_ERROR("timeout during SP initialization");
10106                return -EINVAL;
10107        }
10108
10109        /* Workaround, in order to run two streams in parallel. See TASK 4271*/
10110        /* TODO: Fix this. */
10111
10112        sh_css_init_host_sp_control_vars();
10113
10114        /* buffers should be initialized only when sp is started */
10115        /* AM: At the moment it will be done only when there is no stream active. */
10116
10117        sh_css_setup_queues();
10118        ia_css_bufq_dump_queue_info();
10119
10120        IA_CSS_LEAVE_ERR(err);
10121        return err;
10122}
10123
10124/*
10125    *   Time to wait SP for termincate. Only condition when this can happen
10126    *   is a fatal hw failure, but we must be able to detect this and emit
10127    *   a proper error trace.
10128    */
10129#define SP_SHUTDOWN_TIMEOUT_US 200000
10130
10131int
10132ia_css_stop_sp(void)
10133{
10134        unsigned long timeout;
10135        int err = 0;
10136
10137        IA_CSS_ENTER("void");
10138
10139        if (!sh_css_sp_is_running()) {
10140                err = -EINVAL;
10141                IA_CSS_LEAVE("SP already stopped : return_err=%d", err);
10142
10143                /* Return an error - stop SP should not have been called by driver */
10144                return err;
10145        }
10146
10147        /* For now, stop whole SP */
10148        if (!IS_ISP2401) {
10149                sh_css_write_host2sp_command(host2sp_cmd_terminate);
10150        } else {
10151                if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) {
10152                        IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed");
10153                        ia_css_debug_dump_sp_sw_debug_info();
10154                        ia_css_debug_dump_debug_info(NULL);
10155                }
10156        }
10157
10158        sh_css_sp_set_sp_running(false);
10159
10160        timeout = SP_SHUTDOWN_TIMEOUT_US;
10161        while (!ia_css_spctrl_is_idle(SP0_ID) && timeout) {
10162                timeout--;
10163                udelay(1);
10164        }
10165        if ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED))
10166                IA_CSS_WARNING("SP has not terminated (SW)");
10167
10168        if (timeout == 0) {
10169                IA_CSS_WARNING("SP is not idle");
10170                ia_css_debug_dump_sp_sw_debug_info();
10171        }
10172        timeout = SP_SHUTDOWN_TIMEOUT_US;
10173        while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout) {
10174                timeout--;
10175                udelay(1);
10176        }
10177        if (timeout == 0) {
10178                IA_CSS_WARNING("ISP is not idle");
10179                ia_css_debug_dump_sp_sw_debug_info();
10180        }
10181
10182        sh_css_hmm_buffer_record_uninit();
10183
10184        /* clear pending param sets from refcount */
10185        sh_css_param_clear_param_sets();
10186
10187        IA_CSS_LEAVE_ERR(err);
10188        return err;
10189}
10190
10191int
10192ia_css_update_continuous_frames(struct ia_css_stream *stream)
10193{
10194        struct ia_css_pipe *pipe;
10195        unsigned int i;
10196
10197        ia_css_debug_dtrace(
10198            IA_CSS_DEBUG_TRACE,
10199            "sh_css_update_continuous_frames() enter:\n");
10200
10201        if (!stream) {
10202                ia_css_debug_dtrace(
10203                    IA_CSS_DEBUG_TRACE,
10204                    "sh_css_update_continuous_frames() leave: invalid stream, return_void\n");
10205                return -EINVAL;
10206        }
10207
10208        pipe = stream->continuous_pipe;
10209
10210        for (i = stream->config.init_num_cont_raw_buf;
10211                i < stream->config.target_num_cont_raw_buf; i++)
10212                sh_css_update_host2sp_offline_frame(i,
10213                                                    pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
10214
10215        sh_css_update_host2sp_cont_num_raw_frames
10216        (stream->config.target_num_cont_raw_buf, true);
10217        ia_css_debug_dtrace(
10218            IA_CSS_DEBUG_TRACE,
10219            "sh_css_update_continuous_frames() leave: return_void\n");
10220
10221        return 0;
10222}
10223
10224void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map)
10225{
10226        unsigned int thread_id;
10227        unsigned int pipe_num;
10228        bool need_input_queue;
10229
10230        IA_CSS_ENTER("");
10231        assert(pipe);
10232
10233        pipe_num = pipe->pipe_num;
10234
10235        ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
10236
10237#if defined(ISP2401)
10238        need_input_queue = true;
10239#else
10240        need_input_queue = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
10241#endif
10242
10243        /* map required buffer queues to resources */
10244        /* TODO: to be improved */
10245        if (pipe->mode == IA_CSS_PIPE_ID_PREVIEW) {
10246                if (need_input_queue)
10247                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10248                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10249                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10250                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10251#if defined SH_CSS_ENABLE_METADATA
10252                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10253#endif
10254                if (pipe->pipe_settings.preview.preview_binary.info &&
10255                    pipe->pipe_settings.preview.preview_binary.info->sp.enable.s3a)
10256                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10257        } else if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE) {
10258                unsigned int i;
10259
10260                if (need_input_queue)
10261                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10262                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10263                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map);
10264                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10265                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10266#if defined SH_CSS_ENABLE_METADATA
10267                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10268#endif
10269                if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
10270                        for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
10271                                if (pipe->pipe_settings.capture.primary_binary[i].info &&
10272                                    pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) {
10273                                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10274                                        break;
10275                                }
10276                        }
10277                } else if (pipe->config.default_capture_config.mode ==
10278                            IA_CSS_CAPTURE_MODE_ADVANCED ||
10279                            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT ||
10280                            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) {
10281                        if (pipe->pipe_settings.capture.pre_isp_binary.info &&
10282                            pipe->pipe_settings.capture.pre_isp_binary.info->sp.enable.s3a)
10283                                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10284                }
10285        } else if (pipe->mode == IA_CSS_PIPE_ID_VIDEO) {
10286                if (need_input_queue)
10287                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10288                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10289                if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0])
10290                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map);
10291                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10292                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10293#if defined SH_CSS_ENABLE_METADATA
10294                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10295#endif
10296                if (pipe->pipe_settings.video.video_binary.info &&
10297                    pipe->pipe_settings.video.video_binary.info->sp.enable.s3a)
10298                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10299                if (pipe->pipe_settings.video.video_binary.info &&
10300                    (pipe->pipe_settings.video.video_binary.info->sp.enable.dis
10301                    ))
10302                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_DIS_STATISTICS, map);
10303        } else if (pipe->mode == IA_CSS_PIPE_ID_COPY) {
10304                if (need_input_queue)
10305                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10306                if (!pipe->stream->config.continuous)
10307                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10308#if defined SH_CSS_ENABLE_METADATA
10309                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10310#endif
10311        } else if (pipe->mode == IA_CSS_PIPE_ID_ACC) {
10312                if (need_input_queue)
10313                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10314                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10315                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10316                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10317#if defined SH_CSS_ENABLE_METADATA
10318                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10319#endif
10320        } else if (pipe->mode == IA_CSS_PIPE_ID_YUVPP) {
10321                unsigned int idx;
10322
10323                for (idx = 0; idx < IA_CSS_PIPE_MAX_OUTPUT_STAGE; idx++) {
10324                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, map);
10325                        if (pipe->enable_viewfinder[idx])
10326                                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, map);
10327                }
10328                if (need_input_queue)
10329                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10330                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10331#if defined SH_CSS_ENABLE_METADATA
10332                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10333#endif
10334        }
10335        IA_CSS_LEAVE("");
10336}
10337
10338#if CONFIG_ON_FRAME_ENQUEUE()
10339static int set_config_on_frame_enqueue(struct ia_css_frame_info
10340        *info, struct frame_data_wrapper *frame)
10341{
10342        frame->config_on_frame_enqueue.padded_width = 0;
10343
10344        /* currently we support configuration on frame enqueue only on YUV formats */
10345        /* on other formats the padded_width is zeroed for no configuration override */
10346        switch (info->format) {
10347        case IA_CSS_FRAME_FORMAT_YUV420:
10348        case IA_CSS_FRAME_FORMAT_NV12:
10349                if (info->padded_width > info->res.width)
10350                        frame->config_on_frame_enqueue.padded_width = info->padded_width;
10351                else if ((info->padded_width < info->res.width) && (info->padded_width > 0))
10352                        return -EINVAL;
10353
10354                /* nothing to do if width == padded width or padded width is zeroed (the same) */
10355                break;
10356        default:
10357                break;
10358        }
10359
10360        return 0;
10361}
10362#endif
10363
10364int
10365ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id)
10366{
10367        int ret;
10368
10369        IA_CSS_ENTER("");
10370
10371        /* Only continuous streams have a tagger to which we can send the
10372            * unlock message. */
10373        if (!stream || !stream->config.continuous) {
10374                IA_CSS_ERROR("invalid stream pointer");
10375                return -EINVAL;
10376        }
10377
10378        if (exp_id > IA_CSS_ISYS_MAX_EXPOSURE_ID ||
10379            exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID) {
10380                IA_CSS_ERROR("invalid exposure ID: %d\n", exp_id);
10381                return -EINVAL;
10382        }
10383
10384        /* Send the event. Since we verified that the exp_id is valid,
10385            * we can safely assign it to an 8-bit argument here. */
10386        ret = ia_css_bufq_enqueue_psys_event(
10387            IA_CSS_PSYS_SW_EVENT_UNLOCK_RAW_BUFFER, exp_id, 0, 0);
10388
10389        IA_CSS_LEAVE_ERR(ret);
10390        return ret;
10391}
10392
10393/* @brief       Set the state (Enable or Disable) of the Extension stage in the
10394    *           given pipe.
10395    */
10396int
10397ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
10398                              bool enable)
10399{
10400        unsigned int thread_id;
10401        struct ia_css_pipeline_stage *stage;
10402        int err = 0;
10403
10404        IA_CSS_ENTER("");
10405
10406        /* Parameter Check */
10407        if (!pipe || !pipe->stream) {
10408                IA_CSS_ERROR("Invalid Pipe.");
10409                err = -EINVAL;
10410        } else if (!(pipe->config.acc_extension)) {
10411                IA_CSS_ERROR("Invalid Pipe(No Extension Firmware)");
10412                err = -EINVAL;
10413        } else if (!sh_css_sp_is_running()) {
10414                IA_CSS_ERROR("Leaving: queue unavailable.");
10415                err = -EBUSY;
10416        } else {
10417                /* Query the threadid and stage_num for the Extension firmware*/
10418                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
10419                err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
10420                if (!err) {
10421                        /* Set the Extension State;. TODO: Add check for stage firmware.type (QOS)*/
10422                        err = ia_css_bufq_enqueue_psys_event(
10423                            (uint8_t)IA_CSS_PSYS_SW_EVENT_STAGE_ENABLE_DISABLE,
10424                            (uint8_t)thread_id,
10425                            (uint8_t)stage->stage_num,
10426                            enable ? 1 : 0);
10427                        if (!err) {
10428                                if (enable)
10429                                        SH_CSS_QOS_STAGE_ENABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num);
10430                                else
10431                                        SH_CSS_QOS_STAGE_DISABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num);
10432                        }
10433                }
10434        }
10435        IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, enable);
10436        return err;
10437}
10438
10439/*      @brief  Get the state (Enable or Disable) of the Extension stage in the
10440    *   given pipe.
10441    */
10442int
10443ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
10444                              bool *enable)
10445{
10446        struct ia_css_pipeline_stage *stage;
10447        unsigned int thread_id;
10448        int err = 0;
10449
10450        IA_CSS_ENTER("");
10451
10452        /* Parameter Check */
10453        if (!pipe || !pipe->stream) {
10454                IA_CSS_ERROR("Invalid Pipe.");
10455                err = -EINVAL;
10456        } else if (!(pipe->config.acc_extension)) {
10457                IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
10458                err = -EINVAL;
10459        } else if (!sh_css_sp_is_running()) {
10460                IA_CSS_ERROR("Leaving: queue unavailable.");
10461                err = -EBUSY;
10462        } else {
10463                /* Query the threadid and stage_num corresponding to the Extension firmware*/
10464                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
10465                err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
10466
10467                if (!err) {
10468                        /* Get the Extension State */
10469                        *enable = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id],
10470                                                                stage->stage_num)) ? true : false;
10471                }
10472        }
10473        IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, *enable);
10474        return err;
10475}
10476
10477/* ISP2401 */
10478int
10479ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
10480                                      u32 fw_handle,
10481                                      struct ia_css_isp_param_css_segments *css_seg,
10482                                      struct ia_css_isp_param_isp_segments *isp_seg)
10483{
10484        unsigned int HIVE_ADDR_sp_group;
10485        static struct sh_css_sp_group sp_group;
10486        static struct sh_css_sp_stage sp_stage;
10487        static struct sh_css_isp_stage isp_stage;
10488        const struct ia_css_fw_info *fw;
10489        unsigned int thread_id;
10490        struct ia_css_pipeline_stage *stage;
10491        int err = 0;
10492        int stage_num = 0;
10493        enum ia_css_isp_memories mem;
10494        bool enabled;
10495
10496        IA_CSS_ENTER("");
10497
10498        fw = &sh_css_sp_fw;
10499
10500        /* Parameter Check */
10501        if (!pipe || !pipe->stream) {
10502                IA_CSS_ERROR("Invalid Pipe.");
10503                err = -EINVAL;
10504        } else if (!(pipe->config.acc_extension)) {
10505                IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
10506                err = -EINVAL;
10507        } else if (!sh_css_sp_is_running()) {
10508                IA_CSS_ERROR("Leaving: queue unavailable.");
10509                err = -EBUSY;
10510        } else {
10511                /* Query the thread_id and stage_num corresponding to the Extension firmware */
10512                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
10513                err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
10514                if (!err) {
10515                        /* Get the Extension State */
10516                        enabled = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id],
10517                                                               stage->stage_num)) ? true : false;
10518                        /* Update mapped arg only when extension stage is not enabled */
10519                        if (enabled) {
10520                                IA_CSS_ERROR("Leaving: cannot update when stage is enabled.");
10521                                err = -EBUSY;
10522                        } else {
10523                                stage_num = stage->stage_num;
10524
10525                                HIVE_ADDR_sp_group = fw->info.sp.group;
10526                                sp_dmem_load(SP0_ID,
10527                                             (unsigned int)sp_address_of(sp_group),
10528                                             &sp_group,
10529                                             sizeof(struct sh_css_sp_group));
10530                                hmm_load(sp_group.pipe[thread_id].sp_stage_addr[stage_num],
10531                                         &sp_stage, sizeof(struct sh_css_sp_stage));
10532
10533                                hmm_load(sp_stage.isp_stage_addr,
10534                                         &isp_stage, sizeof(struct sh_css_isp_stage));
10535
10536                                for (mem = 0; mem < N_IA_CSS_ISP_MEMORIES; mem++) {
10537                                        isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address =
10538                                            css_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].address;
10539                                        isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].size =
10540                                            css_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].size;
10541                                        isp_stage.binary_info.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address
10542                                            =
10543                                                isp_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].address;
10544                                        isp_stage.binary_info.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].size
10545                                            =
10546                                                isp_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].size;
10547                                }
10548
10549                                hmm_store(sp_stage.isp_stage_addr,
10550                                          &isp_stage,
10551                                          sizeof(struct sh_css_isp_stage));
10552                        }
10553                }
10554        }
10555        IA_CSS_LEAVE("err:%d handle:%u", err, fw_handle);
10556        return err;
10557}
10558
10559#ifdef ISP2401
10560static int
10561aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
10562                       struct ia_css_pipe *pipes[],
10563                       bool *do_crop_status)
10564{
10565        int err = 0;
10566        int i;
10567        struct ia_css_pipe *curr_pipe;
10568        u32 pipe_mask = 0;
10569
10570        if ((!curr_stream) ||
10571            (curr_stream->num_pipes == 0) ||
10572            (!pipes) ||
10573            (!do_crop_status)) {
10574                err = -EINVAL;
10575                IA_CSS_LEAVE_ERR(err);
10576                return err;
10577        }
10578
10579        for (i = 0; i < curr_stream->num_pipes; i++) {
10580                curr_pipe = pipes[i];
10581                pipe_mask |= (1 << curr_pipe->config.mode);
10582        }
10583
10584        *do_crop_status =
10585        (((pipe_mask & (1 << IA_CSS_PIPE_MODE_PREVIEW)) ||
10586            (pipe_mask & (1 << IA_CSS_PIPE_MODE_VIDEO))) &&
10587            (pipe_mask & (1 << IA_CSS_PIPE_MODE_CAPTURE)) &&
10588            curr_stream->config.continuous);
10589        return 0;
10590}
10591
10592static bool
10593aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe)
10594{
10595        bool status = false;
10596
10597        if ((curr_pipe) && enabled) {
10598                if ((curr_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) ||
10599                    (curr_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) ||
10600                    (curr_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE))
10601                        status = true;
10602        }
10603
10604        return status;
10605}
10606
10607static int
10608aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
10609                  struct ia_css_resolution *effective_res)
10610{
10611        int err = 0;
10612        struct ia_css_resolution crop_res;
10613        struct ia_css_resolution *in_res = NULL;
10614        struct ia_css_resolution *out_res = NULL;
10615        bool use_bds_output_info = false;
10616        bool use_vf_pp_in_res = false;
10617        bool use_capt_pp_in_res = false;
10618
10619        if ((!curr_pipe) ||
10620            (!effective_res)) {
10621                err = -EINVAL;
10622                IA_CSS_LEAVE_ERR(err);
10623                return err;
10624        }
10625
10626        if ((curr_pipe->config.mode != IA_CSS_PIPE_MODE_PREVIEW) &&
10627            (curr_pipe->config.mode != IA_CSS_PIPE_MODE_VIDEO) &&
10628            (curr_pipe->config.mode != IA_CSS_PIPE_MODE_CAPTURE)) {
10629                err = -EINVAL;
10630                IA_CSS_LEAVE_ERR(err);
10631                return err;
10632        }
10633
10634        use_bds_output_info =
10635        ((curr_pipe->bds_output_info.res.width != 0) &&
10636            (curr_pipe->bds_output_info.res.height != 0));
10637
10638        use_vf_pp_in_res =
10639        ((curr_pipe->config.vf_pp_in_res.width != 0) &&
10640            (curr_pipe->config.vf_pp_in_res.height != 0));
10641
10642        use_capt_pp_in_res =
10643        ((curr_pipe->config.capt_pp_in_res.width != 0) &&
10644            (curr_pipe->config.capt_pp_in_res.height != 0));
10645
10646        in_res = &curr_pipe->stream->config.input_config.effective_res;
10647        out_res = &curr_pipe->output_info[0].res;
10648
10649        switch (curr_pipe->config.mode) {
10650        case IA_CSS_PIPE_MODE_PREVIEW:
10651                if (use_bds_output_info)
10652                        out_res = &curr_pipe->bds_output_info.res;
10653                else if (use_vf_pp_in_res)
10654                        out_res = &curr_pipe->config.vf_pp_in_res;
10655                break;
10656        case IA_CSS_PIPE_MODE_VIDEO:
10657                if (use_bds_output_info)
10658                        out_res = &curr_pipe->bds_output_info.res;
10659                break;
10660        case IA_CSS_PIPE_MODE_CAPTURE:
10661                if (use_capt_pp_in_res)
10662                        out_res = &curr_pipe->config.capt_pp_in_res;
10663                break;
10664        case IA_CSS_PIPE_MODE_ACC:
10665        case IA_CSS_PIPE_MODE_COPY:
10666        case IA_CSS_PIPE_MODE_YUVPP:
10667        default:
10668                IA_CSS_ERROR("aspect ratio cropping invalid args: mode[%d]\n",
10669                             curr_pipe->config.mode);
10670                assert(0);
10671                break;
10672        }
10673
10674        err = ia_css_frame_find_crop_resolution(in_res, out_res, &crop_res);
10675        if (!err)
10676                *effective_res = crop_res;
10677        else
10678                /* in case of error fallback to default
10679                    * effective resolution from driver. */
10680                IA_CSS_LOG("ia_css_frame_find_crop_resolution() failed with err(%d)", err);
10681
10682        return err;
10683}
10684#endif
10685
10686static void
10687sh_css_hmm_buffer_record_init(void)
10688{
10689        int i;
10690
10691        for (i = 0; i < MAX_HMM_BUFFER_NUM; i++)
10692                sh_css_hmm_buffer_record_reset(&hmm_buffer_record[i]);
10693}
10694
10695static void
10696sh_css_hmm_buffer_record_uninit(void)
10697{
10698        int i;
10699        struct sh_css_hmm_buffer_record *buffer_record = NULL;
10700
10701        buffer_record = &hmm_buffer_record[0];
10702        for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
10703                if (buffer_record->in_use) {
10704                        if (buffer_record->h_vbuf)
10705                                ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &buffer_record->h_vbuf);
10706                        sh_css_hmm_buffer_record_reset(buffer_record);
10707                }
10708                buffer_record++;
10709        }
10710}
10711
10712static void
10713sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record)
10714{
10715        assert(buffer_record);
10716        buffer_record->in_use = false;
10717        buffer_record->type = IA_CSS_BUFFER_TYPE_INVALID;
10718        buffer_record->h_vbuf = NULL;
10719        buffer_record->kernel_ptr = 0;
10720}
10721
10722static struct sh_css_hmm_buffer_record
10723*sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf,
10724                                    enum ia_css_buffer_type type,
10725                                    hrt_address kernel_ptr)
10726{
10727        int i;
10728        struct sh_css_hmm_buffer_record *buffer_record = NULL;
10729        struct sh_css_hmm_buffer_record *out_buffer_record = NULL;
10730
10731        assert(h_vbuf);
10732        assert((type > IA_CSS_BUFFER_TYPE_INVALID) &&
10733               (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE));
10734        assert(kernel_ptr != 0);
10735
10736        buffer_record = &hmm_buffer_record[0];
10737        for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
10738                if (!buffer_record->in_use) {
10739                        buffer_record->in_use = true;
10740                        buffer_record->type = type;
10741                        buffer_record->h_vbuf = h_vbuf;
10742                        buffer_record->kernel_ptr = kernel_ptr;
10743                        out_buffer_record = buffer_record;
10744                        break;
10745                }
10746                buffer_record++;
10747        }
10748
10749        return out_buffer_record;
10750}
10751
10752static struct sh_css_hmm_buffer_record
10753*sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr,
10754                                    enum ia_css_buffer_type type)
10755{
10756        int i;
10757        struct sh_css_hmm_buffer_record *buffer_record = NULL;
10758        bool found_record = false;
10759
10760        buffer_record = &hmm_buffer_record[0];
10761        for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
10762                if ((buffer_record->in_use) &&
10763                    (buffer_record->type == type) &&
10764                    (buffer_record->h_vbuf) &&
10765                    (buffer_record->h_vbuf->vptr == ddr_buffer_addr)) {
10766                        found_record = true;
10767                        break;
10768                }
10769                buffer_record++;
10770        }
10771
10772        if (found_record)
10773                return buffer_record;
10774        else
10775                return NULL;
10776}
10777