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(const struct ia_css_stream_config *config)
3228{
3229        assert(config);
3230        if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) ||
3231            (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
3232                return 1;
3233
3234        return 0;
3235}
3236
3237static unsigned int
3238get_crop_columns_for_bayer_order(const struct ia_css_stream_config *config)
3239{
3240        assert(config);
3241        if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) ||
3242            (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
3243                return 1;
3244
3245        return 0;
3246}
3247
3248/* This function is to get the sum of all extra pixels in addition to the effective
3249 * input, it includes dvs envelop and filter run-in */
3250static void get_pipe_extra_pixel(struct ia_css_pipe *pipe,
3251                                 unsigned int *extra_row, unsigned int *extra_column)
3252{
3253        enum ia_css_pipe_id pipe_id = pipe->mode;
3254        unsigned int left_cropping = 0, top_cropping = 0;
3255        unsigned int i;
3256        struct ia_css_resolution dvs_env = pipe->config.dvs_envelope;
3257
3258        /* The dvs envelope info may not be correctly sent down via pipe config
3259         * The check is made and the correct value is populated in the binary info
3260         * Use this value when computing crop, else excess lines may get trimmed
3261         */
3262        switch (pipe_id) {
3263        case IA_CSS_PIPE_ID_PREVIEW:
3264                if (pipe->pipe_settings.preview.preview_binary.info) {
3265                        left_cropping =
3266                            pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.left_cropping;
3267                        top_cropping =
3268                            pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.top_cropping;
3269                }
3270                dvs_env = pipe->pipe_settings.preview.preview_binary.dvs_envelope;
3271                break;
3272        case IA_CSS_PIPE_ID_VIDEO:
3273                if (pipe->pipe_settings.video.video_binary.info) {
3274                        left_cropping =
3275                            pipe->pipe_settings.video.video_binary.info->sp.pipeline.left_cropping;
3276                        top_cropping =
3277                            pipe->pipe_settings.video.video_binary.info->sp.pipeline.top_cropping;
3278                }
3279                dvs_env = pipe->pipe_settings.video.video_binary.dvs_envelope;
3280                break;
3281        case IA_CSS_PIPE_ID_CAPTURE:
3282                for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
3283                        if (pipe->pipe_settings.capture.primary_binary[i].info) {
3284                                left_cropping +=
3285                                    pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.left_cropping;
3286                                top_cropping +=
3287                                    pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.top_cropping;
3288                        }
3289                        dvs_env.width +=
3290                            pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.width;
3291                        dvs_env.height +=
3292                            pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.height;
3293                }
3294                break;
3295        default:
3296                break;
3297        }
3298
3299        *extra_row = top_cropping + dvs_env.height;
3300        *extra_column = left_cropping + dvs_env.width;
3301}
3302
3303void
3304ia_css_get_crop_offsets(
3305    struct ia_css_pipe *pipe,
3306    struct ia_css_frame_info *in_frame)
3307{
3308        unsigned int row = 0;
3309        unsigned int column = 0;
3310        struct ia_css_resolution *input_res;
3311        struct ia_css_resolution *effective_res;
3312        unsigned int extra_row = 0, extra_col = 0;
3313        unsigned int min_reqd_height, min_reqd_width;
3314
3315        assert(pipe);
3316        assert(pipe->stream);
3317        assert(in_frame);
3318
3319        IA_CSS_ENTER_PRIVATE("pipe = %p effective_wd = %u effective_ht = %u",
3320                             pipe, pipe->config.input_effective_res.width,
3321                             pipe->config.input_effective_res.height);
3322
3323        input_res = &pipe->stream->config.input_config.input_res;
3324#ifndef ISP2401
3325        effective_res = &pipe->stream->config.input_config.effective_res;
3326#else
3327        effective_res = &pipe->config.input_effective_res;
3328#endif
3329
3330        get_pipe_extra_pixel(pipe, &extra_row, &extra_col);
3331
3332        in_frame->raw_bayer_order = pipe->stream->config.input_config.bayer_order;
3333
3334        min_reqd_height = effective_res->height + extra_row;
3335        min_reqd_width = effective_res->width + extra_col;
3336
3337        if (input_res->height > min_reqd_height) {
3338                row = (input_res->height - min_reqd_height) / 2;
3339                row &= ~0x1;
3340        }
3341        if (input_res->width > min_reqd_width) {
3342                column = (input_res->width - min_reqd_width) / 2;
3343                column &= ~0x1;
3344        }
3345
3346        /*
3347         * TODO:
3348         * 1. Require the special support for RAW10 packed mode.
3349         * 2. Require the special support for the online use cases.
3350         */
3351
3352        /* ISP expects GRBG bayer order, we skip one line and/or one row
3353         * to correct in case the input bayer order is different.
3354         */
3355        column += get_crop_columns_for_bayer_order(&pipe->stream->config);
3356        row += get_crop_lines_for_bayer_order(&pipe->stream->config);
3357
3358        in_frame->crop_info.start_column = column;
3359        in_frame->crop_info.start_line = row;
3360
3361        IA_CSS_LEAVE_PRIVATE("void start_col: %u start_row: %u", column, row);
3362
3363        return;
3364}
3365#endif
3366
3367static int
3368init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
3369                                  struct ia_css_frame *frame, enum ia_css_frame_format format)
3370{
3371        struct ia_css_frame *in_frame;
3372        int err = 0;
3373        unsigned int thread_id;
3374        enum sh_css_queue_id queue_id;
3375
3376        assert(frame);
3377        in_frame = frame;
3378
3379        in_frame->info.format = format;
3380
3381#ifdef ISP2401
3382        if (format == IA_CSS_FRAME_FORMAT_RAW)
3383                in_frame->info.format = (pipe->stream->config.pack_raw_pixels) ?
3384                IA_CSS_FRAME_FORMAT_RAW_PACKED : IA_CSS_FRAME_FORMAT_RAW;
3385#endif
3386
3387        in_frame->info.res.width = pipe->stream->config.input_config.input_res.width;
3388        in_frame->info.res.height = pipe->stream->config.input_config.input_res.height;
3389        in_frame->info.raw_bit_depth =
3390        ia_css_pipe_util_pipe_input_format_bpp(pipe);
3391        ia_css_frame_info_set_width(&in_frame->info, pipe->stream->config.input_config.input_res.width, 0);
3392        in_frame->contiguous = false;
3393        in_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3394        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3395        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id);
3396        in_frame->dynamic_queue_id = queue_id;
3397        in_frame->buf_type = IA_CSS_BUFFER_TYPE_INPUT_FRAME;
3398#ifdef ISP2401
3399        ia_css_get_crop_offsets(pipe, &in_frame->info);
3400#endif
3401        err = ia_css_frame_init_planes(in_frame);
3402
3403        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3404                            "init_in_frameinfo_memory_defaults() bayer_order = %d:\n", in_frame->info.raw_bayer_order);
3405
3406        return err;
3407}
3408
3409static int
3410init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
3411                            struct ia_css_frame *out_frame, unsigned int idx)
3412{
3413        int err = 0;
3414        unsigned int thread_id;
3415        enum sh_css_queue_id queue_id;
3416
3417        assert(out_frame);
3418
3419        sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, idx);
3420        out_frame->contiguous = false;
3421        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3422        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3423        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, thread_id, &queue_id);
3424        out_frame->dynamic_queue_id = queue_id;
3425        out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx;
3426        err = ia_css_frame_init_planes(out_frame);
3427
3428        return err;
3429}
3430
3431/* Create stages for video pipe */
3432static int create_host_video_pipeline(struct ia_css_pipe *pipe)
3433{
3434        struct ia_css_pipeline_stage_desc stage_desc;
3435        struct ia_css_binary *copy_binary, *video_binary,
3436                       *yuv_scaler_binary, *vf_pp_binary;
3437        struct ia_css_pipeline_stage *copy_stage  = NULL;
3438        struct ia_css_pipeline_stage *video_stage = NULL;
3439        struct ia_css_pipeline_stage *yuv_scaler_stage  = NULL;
3440        struct ia_css_pipeline_stage *vf_pp_stage = NULL;
3441        struct ia_css_pipeline *me;
3442        struct ia_css_frame *in_frame = NULL;
3443        struct ia_css_frame *out_frame;
3444        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3445        struct ia_css_frame *vf_frame = NULL;
3446        int err = 0;
3447        bool need_copy   = false;
3448        bool need_vf_pp  = false;
3449        bool need_yuv_pp = false;
3450        bool need_in_frameinfo_memory = false;
3451
3452        unsigned int i, num_yuv_scaler;
3453        bool *is_output_stage = NULL;
3454
3455        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3456        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
3457                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3458                return -EINVAL;
3459        }
3460        ia_css_pipe_util_create_output_frames(out_frames);
3461        out_frame = &pipe->out_frame_struct;
3462
3463        /* pipeline already created as part of create_host_pipeline_structure */
3464        me = &pipe->pipeline;
3465        ia_css_pipeline_clean(me);
3466
3467        me->dvs_frame_delay = pipe->dvs_frame_delay;
3468
3469#ifdef ISP2401
3470        /* When the input system is 2401, always enable 'in_frameinfo_memory'
3471         * except for the following: online or continuous
3472         */
3473        need_in_frameinfo_memory = !(pipe->stream->config.online ||
3474                                     pipe->stream->config.continuous);
3475#else
3476        /* Construct in_frame info (only in case we have dynamic input */
3477        need_in_frameinfo_memory = pipe->stream->config.mode ==
3478                                   IA_CSS_INPUT_MODE_MEMORY;
3479#endif
3480
3481        /* Construct in_frame info (only in case we have dynamic input */
3482        if (need_in_frameinfo_memory) {
3483                in_frame = &pipe->in_frame_struct;
3484                err = init_in_frameinfo_memory_defaults(pipe, in_frame,
3485                                                        IA_CSS_FRAME_FORMAT_RAW);
3486                if (err)
3487                        goto ERR;
3488        }
3489
3490        out_frame->data = 0;
3491        err = init_out_frameinfo_defaults(pipe, out_frame, 0);
3492        if (err)
3493                goto ERR;
3494
3495        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
3496                vf_frame = &pipe->vf_frame_struct;
3497                vf_frame->data = 0;
3498                err = init_vf_frameinfo_defaults(pipe, vf_frame, 0);
3499                if (err)
3500                        goto ERR;
3501        }
3502
3503        copy_binary  = &pipe->pipe_settings.video.copy_binary;
3504        video_binary = &pipe->pipe_settings.video.video_binary;
3505        vf_pp_binary = &pipe->pipe_settings.video.vf_pp_binary;
3506
3507        yuv_scaler_binary = pipe->pipe_settings.video.yuv_scaler_binary;
3508        num_yuv_scaler  = pipe->pipe_settings.video.num_yuv_scaler;
3509        is_output_stage = pipe->pipe_settings.video.is_output_stage;
3510
3511        need_copy   = (copy_binary && copy_binary->info);
3512        need_vf_pp  = (vf_pp_binary && vf_pp_binary->info);
3513        need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
3514
3515        if (need_copy) {
3516                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3517                ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
3518                                                   out_frames, NULL, NULL);
3519                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3520                                                           &copy_stage);
3521                if (err)
3522                        goto ERR;
3523                in_frame = me->stages->args.out_frame[0];
3524        } else if (pipe->stream->config.continuous) {
3525#ifdef ISP2401
3526                /* When continuous is enabled, configure in_frame with the
3527                 * last pipe, which is the copy pipe.
3528                 */
3529                in_frame = pipe->stream->last_pipe->continuous_frames[0];
3530#else
3531                in_frame = pipe->continuous_frames[0];
3532#endif
3533        }
3534
3535        ia_css_pipe_util_set_output_frames(out_frames, 0,
3536                                           need_yuv_pp ? NULL : out_frame);
3537
3538        /* when the video binary supports a second output pin,
3539           it can directly produce the vf_frame.  */
3540        if (need_vf_pp) {
3541                ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
3542                                                   out_frames, in_frame, NULL);
3543        } else {
3544                ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
3545                                                   out_frames, in_frame, vf_frame);
3546        }
3547        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3548                                                   &video_stage);
3549        if (err)
3550                goto ERR;
3551
3552        /* If we use copy iso video, the input must be yuv iso raw */
3553        if (video_stage) {
3554                video_stage->args.copy_vf =
3555                    video_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
3556                video_stage->args.copy_output = video_stage->args.copy_vf;
3557        }
3558
3559        /* when the video binary supports only 1 output pin, vf_pp is needed to
3560        produce the vf_frame.*/
3561        if (need_vf_pp && video_stage) {
3562                in_frame = video_stage->args.out_vf_frame;
3563                err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
3564                                      &vf_pp_stage);
3565                if (err)
3566                        goto ERR;
3567        }
3568        if (video_stage) {
3569                int frm;
3570
3571                for (frm = 0; frm < NUM_TNR_FRAMES; frm++) {
3572                        video_stage->args.tnr_frames[frm] =
3573                            pipe->pipe_settings.video.tnr_frames[frm];
3574                }
3575                for (frm = 0; frm < MAX_NUM_VIDEO_DELAY_FRAMES; frm++) {
3576                        video_stage->args.delay_frames[frm] =
3577                            pipe->pipe_settings.video.delay_frames[frm];
3578                }
3579        }
3580
3581        /* Append Extension on Video out, if enabled */
3582        if (!need_vf_pp && video_stage && pipe->config.acc_extension &&
3583            (pipe->config.acc_extension->info.isp.type == IA_CSS_ACC_OUTPUT)) {
3584                struct ia_css_frame *out = NULL;
3585                struct ia_css_frame *in = NULL;
3586
3587                if ((pipe->config.acc_extension->info.isp.sp.enable.output) &&
3588                    (pipe->config.acc_extension->info.isp.sp.enable.in_frame) &&
3589                    (pipe->config.acc_extension->info.isp.sp.enable.out_frame)) {
3590                        /* In/Out Frame mapping to support output frame extension.*/
3591                        out = video_stage->args.out_frame[0];
3592                        err = ia_css_frame_allocate_from_info(&in, &pipe->output_info[0]);
3593                        if (err)
3594                                goto ERR;
3595                        video_stage->args.out_frame[0] = in;
3596                }
3597
3598                err = add_firmwares(me, video_binary, pipe->output_stage,
3599                                    last_output_firmware(pipe->output_stage),
3600                                    IA_CSS_BINARY_MODE_VIDEO,
3601                                    in, out, NULL, &video_stage, NULL);
3602                if (err)
3603                        goto ERR;
3604        }
3605
3606        if (need_yuv_pp && video_stage) {
3607                struct ia_css_frame *tmp_in_frame = video_stage->args.out_frame[0];
3608                struct ia_css_frame *tmp_out_frame = NULL;
3609
3610                for (i = 0; i < num_yuv_scaler; i++) {
3611                        tmp_out_frame = is_output_stage[i] ? out_frame : NULL;
3612
3613                        err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
3614                                                   tmp_out_frame, NULL,
3615                                                   &yuv_scaler_binary[i],
3616                                                   &yuv_scaler_stage);
3617
3618                        if (err) {
3619                                IA_CSS_LEAVE_ERR_PRIVATE(err);
3620                                return err;
3621                        }
3622                        /* we use output port 1 as internal output port */
3623                        if (yuv_scaler_stage)
3624                                tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
3625                }
3626        }
3627
3628        pipe->pipeline.acquire_isp_each_stage = false;
3629        ia_css_pipeline_finalize_stages(&pipe->pipeline,
3630                                        pipe->stream->config.continuous);
3631
3632ERR:
3633        IA_CSS_LEAVE_ERR_PRIVATE(err);
3634        return err;
3635}
3636
3637static int
3638create_host_acc_pipeline(struct ia_css_pipe *pipe)
3639{
3640        int err = 0;
3641        const struct ia_css_fw_info *fw;
3642        unsigned int i;
3643
3644        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3645        if ((!pipe) || (!pipe->stream)) {
3646                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3647                return -EINVAL;
3648        }
3649
3650        pipe->pipeline.num_execs = pipe->config.acc_num_execs;
3651        /* Reset pipe_qos_config to default disable all QOS extension stages */
3652        if (pipe->config.acc_extension)
3653                pipe->pipeline.pipe_qos_config = 0;
3654
3655        fw = pipe->vf_stage;
3656        for (i = 0; fw; fw = fw->next) {
3657                err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
3658                if (err)
3659                        goto ERR;
3660        }
3661
3662        for (i = 0; i < pipe->config.num_acc_stages; i++) {
3663                struct ia_css_fw_info *fw = pipe->config.acc_stages[i];
3664
3665                err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
3666                if (err)
3667                        goto ERR;
3668        }
3669
3670        ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
3671
3672ERR:
3673        IA_CSS_LEAVE_ERR_PRIVATE(err);
3674        return err;
3675}
3676
3677/* Create stages for preview */
3678static int
3679create_host_preview_pipeline(struct ia_css_pipe *pipe)
3680{
3681        struct ia_css_pipeline_stage *copy_stage = NULL;
3682        struct ia_css_pipeline_stage *preview_stage = NULL;
3683        struct ia_css_pipeline_stage *vf_pp_stage = NULL;
3684        struct ia_css_pipeline_stage_desc stage_desc;
3685        struct ia_css_pipeline *me = NULL;
3686        struct ia_css_binary *copy_binary, *preview_binary, *vf_pp_binary = NULL;
3687        struct ia_css_frame *in_frame = NULL;
3688        int err = 0;
3689        struct ia_css_frame *out_frame;
3690        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3691        bool need_in_frameinfo_memory = false;
3692#ifdef ISP2401
3693        bool sensor = false;
3694        bool buffered_sensor = false;
3695        bool online = false;
3696        bool continuous = false;
3697#endif
3698
3699        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3700        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
3701                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3702                return -EINVAL;
3703        }
3704
3705        ia_css_pipe_util_create_output_frames(out_frames);
3706        /* pipeline already created as part of create_host_pipeline_structure */
3707        me = &pipe->pipeline;
3708        ia_css_pipeline_clean(me);
3709
3710#ifdef ISP2401
3711        /* When the input system is 2401, always enable 'in_frameinfo_memory'
3712         * except for the following:
3713         * - Direct Sensor Mode Online Preview
3714         * - Buffered Sensor Mode Online Preview
3715         * - Direct Sensor Mode Continuous Preview
3716         * - Buffered Sensor Mode Continuous Preview
3717         */
3718        sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
3719        buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
3720        online = pipe->stream->config.online;
3721        continuous = pipe->stream->config.continuous;
3722        need_in_frameinfo_memory =
3723        !((sensor && (online || continuous)) || (buffered_sensor && (online || continuous)));
3724#else
3725        /* Construct in_frame info (only in case we have dynamic input */
3726        need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
3727#endif
3728        if (need_in_frameinfo_memory) {
3729                err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
3730                                                        IA_CSS_FRAME_FORMAT_RAW);
3731                if (err)
3732                        goto ERR;
3733
3734                in_frame = &me->in_frame;
3735        } else {
3736                in_frame = NULL;
3737        }
3738
3739        err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
3740        if (err)
3741                goto ERR;
3742        out_frame = &me->out_frame[0];
3743
3744        copy_binary    = &pipe->pipe_settings.preview.copy_binary;
3745        preview_binary = &pipe->pipe_settings.preview.preview_binary;
3746        if (pipe->pipe_settings.preview.vf_pp_binary.info)
3747                vf_pp_binary = &pipe->pipe_settings.preview.vf_pp_binary;
3748
3749        if (pipe->pipe_settings.preview.copy_binary.info) {
3750                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3751                ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
3752                                                   out_frames, NULL, NULL);
3753                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3754                                                           &copy_stage);
3755                if (err)
3756                        goto ERR;
3757                in_frame = me->stages->args.out_frame[0];
3758        } else if (pipe->stream->config.continuous) {
3759#ifdef ISP2401
3760                /* When continuous is enabled, configure in_frame with the
3761                 * last pipe, which is the copy pipe.
3762                 */
3763                if (continuous || !online)
3764                        in_frame = pipe->stream->last_pipe->continuous_frames[0];
3765
3766#else
3767                in_frame = pipe->continuous_frames[0];
3768#endif
3769        }
3770
3771        if (vf_pp_binary) {
3772                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3773                ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
3774                                                   out_frames, in_frame, NULL);
3775        } else {
3776                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3777                ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
3778                                                   out_frames, in_frame, NULL);
3779        }
3780        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3781                                                   &preview_stage);
3782        if (err)
3783                goto ERR;
3784        /* If we use copy iso preview, the input must be yuv iso raw */
3785        preview_stage->args.copy_vf =
3786            preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
3787        preview_stage->args.copy_output = !preview_stage->args.copy_vf;
3788        if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) {
3789                /* in case of copy, use the vf frame as output frame */
3790                preview_stage->args.out_vf_frame =
3791                    preview_stage->args.out_frame[0];
3792        }
3793        if (vf_pp_binary) {
3794                if (preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)
3795                        in_frame = preview_stage->args.out_vf_frame;
3796                else
3797                        in_frame = preview_stage->args.out_frame[0];
3798                err = add_vf_pp_stage(pipe, in_frame, out_frame, vf_pp_binary,
3799                                      &vf_pp_stage);
3800                if (err)
3801                        goto ERR;
3802        }
3803
3804        pipe->pipeline.acquire_isp_each_stage = false;
3805        ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
3806
3807ERR:
3808        IA_CSS_LEAVE_ERR_PRIVATE(err);
3809        return err;
3810}
3811
3812static void send_raw_frames(struct ia_css_pipe *pipe)
3813{
3814        if (pipe->stream->config.continuous) {
3815                unsigned int i;
3816
3817                sh_css_update_host2sp_cont_num_raw_frames
3818                (pipe->stream->config.init_num_cont_raw_buf, true);
3819                sh_css_update_host2sp_cont_num_raw_frames
3820                (pipe->stream->config.target_num_cont_raw_buf, false);
3821
3822                /* Hand-over all the SP-internal buffers */
3823                for (i = 0; i < pipe->stream->config.init_num_cont_raw_buf; i++) {
3824                        sh_css_update_host2sp_offline_frame(i,
3825                                                            pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
3826                }
3827        }
3828
3829        return;
3830}
3831
3832static int
3833preview_start(struct ia_css_pipe *pipe)
3834{
3835        int err = 0;
3836        struct ia_css_pipe *copy_pipe, *capture_pipe;
3837        struct ia_css_pipe *acc_pipe;
3838        enum sh_css_pipe_config_override copy_ovrd;
3839        enum ia_css_input_mode preview_pipe_input_mode;
3840        const struct ia_css_coordinate *coord = NULL;
3841        const struct ia_css_isp_parameters *params = NULL;
3842
3843        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3844        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
3845                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3846                return -EINVAL;
3847        }
3848
3849        preview_pipe_input_mode = pipe->stream->config.mode;
3850
3851        copy_pipe    = pipe->pipe_settings.preview.copy_pipe;
3852        capture_pipe = pipe->pipe_settings.preview.capture_pipe;
3853        acc_pipe     = pipe->pipe_settings.preview.acc_pipe;
3854
3855        sh_css_metrics_start_frame();
3856
3857        /* multi stream video needs mipi buffers */
3858        err = send_mipi_frames(pipe);
3859        if (err) {
3860                IA_CSS_LEAVE_ERR_PRIVATE(err);
3861                return err;
3862        }
3863        send_raw_frames(pipe);
3864
3865        {
3866                unsigned int thread_id;
3867
3868                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3869                copy_ovrd = 1 << thread_id;
3870
3871                if (pipe->stream->cont_capt) {
3872                        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
3873                                                         &thread_id);
3874                        copy_ovrd |= 1 << thread_id;
3875                }
3876        }
3877
3878        if (IS_ISP2401) {
3879                coord = &pipe->config.internal_frame_origin_bqs_on_sctbl;
3880                params = pipe->stream->isp_params_configs;
3881        }
3882
3883        /* Construct and load the copy pipe */
3884        if (pipe->stream->config.continuous) {
3885                sh_css_sp_init_pipeline(&copy_pipe->pipeline,
3886                                        IA_CSS_PIPE_ID_COPY,
3887                                        (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
3888                                        false,
3889                                        pipe->stream->config.pixels_per_clock == 2, false,
3890                                        false, pipe->required_bds_factor,
3891                                        copy_ovrd,
3892                                        pipe->stream->config.mode,
3893                                        &pipe->stream->config.metadata_config,
3894                                        &pipe->stream->info.metadata_info,
3895                                        pipe->stream->config.source.port.port,
3896                                        coord,
3897                                        params);
3898
3899                /* make the preview pipe start with mem mode input, copy handles
3900                   the actual mode */
3901                preview_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY;
3902        }
3903
3904        /* Construct and load the capture pipe */
3905        if (pipe->stream->cont_capt) {
3906                sh_css_sp_init_pipeline(&capture_pipe->pipeline,
3907                                        IA_CSS_PIPE_ID_CAPTURE,
3908                                        (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
3909                                        capture_pipe->config.default_capture_config.enable_xnr != 0,
3910                                        capture_pipe->stream->config.pixels_per_clock == 2,
3911                                        true, /* continuous */
3912                                        false, /* offline */
3913                                        capture_pipe->required_bds_factor,
3914                                        0,
3915                                        IA_CSS_INPUT_MODE_MEMORY,
3916                                        &pipe->stream->config.metadata_config,
3917                                        &pipe->stream->info.metadata_info,
3918                                        (enum mipi_port_id)0,
3919                                        coord,
3920                                        params);
3921        }
3922
3923        if (acc_pipe) {
3924                sh_css_sp_init_pipeline(&acc_pipe->pipeline,
3925                                        IA_CSS_PIPE_ID_ACC,
3926                                        (uint8_t)ia_css_pipe_get_pipe_num(acc_pipe),
3927                                        false,
3928                                        pipe->stream->config.pixels_per_clock == 2,
3929                                        false, /* continuous */
3930                                        false, /* offline */
3931                                        pipe->required_bds_factor,
3932                                        0,
3933                                        IA_CSS_INPUT_MODE_MEMORY,
3934                                        NULL,
3935                                        NULL,
3936                                        (enum mipi_port_id)0,
3937                                        coord,
3938                                        params);
3939        }
3940
3941        start_pipe(pipe, copy_ovrd, preview_pipe_input_mode);
3942
3943        IA_CSS_LEAVE_ERR_PRIVATE(err);
3944        return err;
3945}
3946
3947int
3948ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
3949                           const struct ia_css_buffer *buffer)
3950{
3951        int return_err = 0;
3952        unsigned int thread_id;
3953        enum sh_css_queue_id queue_id;
3954        struct ia_css_pipeline *pipeline;
3955        struct ia_css_pipeline_stage *stage;
3956        struct ia_css_rmgr_vbuf_handle p_vbuf;
3957        struct ia_css_rmgr_vbuf_handle *h_vbuf;
3958        struct sh_css_hmm_buffer ddr_buffer;
3959        enum ia_css_buffer_type buf_type;
3960        enum ia_css_pipe_id pipe_id;
3961        bool ret_err;
3962
3963        IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
3964
3965        if ((!pipe) || (!buffer)) {
3966                IA_CSS_LEAVE_ERR(-EINVAL);
3967                return -EINVAL;
3968        }
3969
3970        buf_type = buffer->type;
3971        /* following code will be enabled when IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
3972           is removed */
3973#if 0
3974        if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
3975                bool found_pipe = false;
3976
3977                for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
3978                        if ((buffer->data.frame->info.res.width == pipe->output_info[i].res.width) &&
3979                            (buffer->data.frame->info.res.height == pipe->output_info[i].res.height)) {
3980                                buf_type += i;
3981                                found_pipe = true;
3982                                break;
3983                        }
3984                }
3985                if (!found_pipe)
3986                        return -EINVAL;
3987        }
3988        if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
3989                bool found_pipe = false;
3990
3991                for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
3992                        if ((buffer->data.frame->info.res.width == pipe->vf_output_info[i].res.width) &&
3993                            (buffer->data.frame->info.res.height == pipe->vf_output_info[i].res.height)) {
3994                                buf_type += i;
3995                                found_pipe = true;
3996                                break;
3997                        }
3998                }
3999                if (!found_pipe)
4000                        return -EINVAL;
4001        }
4002#endif
4003        pipe_id = pipe->mode;
4004
4005        IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type);
4006
4007        assert(pipe_id < IA_CSS_PIPE_ID_NUM);
4008        assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
4009        if (buf_type == IA_CSS_BUFFER_TYPE_INVALID ||
4010            buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE ||
4011            pipe_id >= IA_CSS_PIPE_ID_NUM) {
4012                IA_CSS_LEAVE_ERR(-EINVAL);
4013                return -EINVAL;
4014        }
4015
4016        ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4017        if (!ret_err) {
4018                IA_CSS_LEAVE_ERR(-EINVAL);
4019                return -EINVAL;
4020        }
4021
4022        ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
4023        if (!ret_err) {
4024                IA_CSS_LEAVE_ERR(-EINVAL);
4025                return -EINVAL;
4026        }
4027
4028        if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
4029                IA_CSS_LEAVE_ERR(-EINVAL);
4030                return -EINVAL;
4031        }
4032
4033        if (!sh_css_sp_is_running()) {
4034                IA_CSS_LOG("SP is not running!");
4035                IA_CSS_LEAVE_ERR(-EBUSY);
4036                /* SP is not running. The queues are not valid */
4037                return -EBUSY;
4038        }
4039
4040        pipeline = &pipe->pipeline;
4041
4042        assert(pipeline ||
4043               pipe_id == IA_CSS_PIPE_ID_COPY ||
4044               pipe_id == IA_CSS_PIPE_ID_ACC);
4045
4046        assert(sizeof(NULL) <= sizeof(ddr_buffer.kernel_ptr));
4047        ddr_buffer.kernel_ptr = HOST_ADDRESS(NULL);
4048        ddr_buffer.cookie_ptr = buffer->driver_cookie;
4049        ddr_buffer.timing_data = buffer->timing_data;
4050
4051        if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) {
4052                if (!buffer->data.stats_3a) {
4053                        IA_CSS_LEAVE_ERR(-EINVAL);
4054                        return -EINVAL;
4055                }
4056                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_3a);
4057                ddr_buffer.payload.s3a = *buffer->data.stats_3a;
4058        } else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) {
4059                if (!buffer->data.stats_dvs) {
4060                        IA_CSS_LEAVE_ERR(-EINVAL);
4061                        return -EINVAL;
4062                }
4063                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_dvs);
4064                ddr_buffer.payload.dis = *buffer->data.stats_dvs;
4065        } else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
4066                if (!buffer->data.metadata) {
4067                        IA_CSS_LEAVE_ERR(-EINVAL);
4068                        return -EINVAL;
4069                }
4070                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.metadata);
4071                ddr_buffer.payload.metadata = *buffer->data.metadata;
4072        } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
4073                   buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
4074                   buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
4075                   buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
4076                   buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) {
4077                if (!buffer->data.frame) {
4078                        IA_CSS_LEAVE_ERR(-EINVAL);
4079                        return -EINVAL;
4080                }
4081                ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.frame);
4082                ddr_buffer.payload.frame.frame_data = buffer->data.frame->data;
4083                ddr_buffer.payload.frame.flashed = 0;
4084
4085                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4086                                    "ia_css_pipe_enqueue_buffer() buf_type=%d, data(DDR address)=0x%x\n",
4087                                    buf_type, buffer->data.frame->data);
4088
4089#if CONFIG_ON_FRAME_ENQUEUE()
4090                return_err = set_config_on_frame_enqueue(
4091                                 &buffer->data.frame->info,
4092                                 &ddr_buffer.payload.frame);
4093                if (return_err) {
4094                        IA_CSS_LEAVE_ERR(return_err);
4095                        return return_err;
4096                }
4097#endif
4098        }
4099
4100        /* start of test for using rmgr for acq/rel memory */
4101        p_vbuf.vptr = 0;
4102        p_vbuf.count = 0;
4103        p_vbuf.size = sizeof(struct sh_css_hmm_buffer);
4104        h_vbuf = &p_vbuf;
4105        /* TODO: change next to correct pool for optimization */
4106        ia_css_rmgr_acq_vbuf(hmm_buffer_pool, &h_vbuf);
4107
4108        if ((!h_vbuf) || (h_vbuf->vptr == 0x0)) {
4109                IA_CSS_LEAVE_ERR(-EINVAL);
4110                return -EINVAL;
4111        }
4112
4113        hmm_store(h_vbuf->vptr,
4114                  (void *)(&ddr_buffer),
4115                  sizeof(struct sh_css_hmm_buffer));
4116        if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS ||
4117            buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS ||
4118            buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS) {
4119                if (!pipeline) {
4120                        ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
4121                        IA_CSS_LOG("pipeline is empty!");
4122                        IA_CSS_LEAVE_ERR(-EINVAL);
4123                        return -EINVAL;
4124                }
4125
4126                for (stage = pipeline->stages; stage; stage = stage->next) {
4127                        /* The SP will read the params
4128                                after it got empty 3a and dis */
4129                        if (STATS_ENABLED(stage)) {
4130                                /* there is a stage that needs it */
4131                                return_err = ia_css_bufq_enqueue_buffer(thread_id,
4132                                                                        queue_id,
4133                                                                        (uint32_t)h_vbuf->vptr);
4134                        }
4135                }
4136        } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
4137                   buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
4138                   buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
4139                   buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
4140                   buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME ||
4141                   buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
4142                return_err = ia_css_bufq_enqueue_buffer(thread_id,
4143                                                        queue_id,
4144                                                        (uint32_t)h_vbuf->vptr);
4145#if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS)
4146                if (!return_err &&
4147                    buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
4148                        IA_CSS_LOG("pfp: enqueued OF %d to q %d thread %d",
4149                                   ddr_buffer.payload.frame.frame_data,
4150                                   queue_id, thread_id);
4151                }
4152#endif
4153        }
4154
4155        if (!return_err) {
4156                if (sh_css_hmm_buffer_record_acquire(
4157                        h_vbuf, buf_type,
4158                        HOST_ADDRESS(ddr_buffer.kernel_ptr))) {
4159                        IA_CSS_LOG("send vbuf=%p", h_vbuf);
4160                } else {
4161                        return_err = -EINVAL;
4162                        IA_CSS_ERROR("hmm_buffer_record[]: no available slots\n");
4163                }
4164        }
4165
4166        /*
4167         * Tell the SP which queues are not empty,
4168         * by sending the software event.
4169         */
4170        if (!return_err) {
4171                if (!sh_css_sp_is_running()) {
4172                        /* SP is not running. The queues are not valid */
4173                        IA_CSS_LOG("SP is not running!");
4174                        IA_CSS_LEAVE_ERR(-EBUSY);
4175                        return -EBUSY;
4176                }
4177                return_err = ia_css_bufq_enqueue_psys_event(
4178                                 IA_CSS_PSYS_SW_EVENT_BUFFER_ENQUEUED,
4179                                 (uint8_t)thread_id,
4180                                 queue_id,
4181                                 0);
4182        } else {
4183                ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
4184                IA_CSS_ERROR("buffer not enqueued");
4185        }
4186
4187        IA_CSS_LEAVE("return value = %d", return_err);
4188
4189        return return_err;
4190}
4191
4192/*
4193 * TODO: Free up the hmm memory space.
4194         */
4195int
4196ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
4197                           struct ia_css_buffer *buffer)
4198{
4199        int return_err;
4200        enum sh_css_queue_id queue_id;
4201        ia_css_ptr ddr_buffer_addr = (ia_css_ptr)0;
4202        struct sh_css_hmm_buffer ddr_buffer;
4203        enum ia_css_buffer_type buf_type;
4204        enum ia_css_pipe_id pipe_id;
4205        unsigned int thread_id;
4206        hrt_address kernel_ptr = 0;
4207        bool ret_err;
4208
4209        IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
4210
4211        if ((!pipe) || (!buffer)) {
4212                IA_CSS_LEAVE_ERR(-EINVAL);
4213                return -EINVAL;
4214        }
4215
4216        pipe_id = pipe->mode;
4217
4218        buf_type = buffer->type;
4219
4220        IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type);
4221
4222        ddr_buffer.kernel_ptr = 0;
4223
4224        ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4225        if (!ret_err) {
4226                IA_CSS_LEAVE_ERR(-EINVAL);
4227                return -EINVAL;
4228        }
4229
4230        ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
4231        if (!ret_err) {
4232                IA_CSS_LEAVE_ERR(-EINVAL);
4233                return -EINVAL;
4234        }
4235
4236        if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
4237                IA_CSS_LEAVE_ERR(-EINVAL);
4238                return -EINVAL;
4239        }
4240
4241        if (!sh_css_sp_is_running()) {
4242                IA_CSS_LOG("SP is not running!");
4243                IA_CSS_LEAVE_ERR(-EBUSY);
4244                /* SP is not running. The queues are not valid */
4245                return -EBUSY;
4246        }
4247
4248        return_err = ia_css_bufq_dequeue_buffer(queue_id,
4249                                                (uint32_t *)&ddr_buffer_addr);
4250
4251        if (!return_err) {
4252                struct ia_css_frame *frame;
4253                struct sh_css_hmm_buffer_record *hmm_buffer_record = NULL;
4254
4255                IA_CSS_LOG("receive vbuf=%x", (int)ddr_buffer_addr);
4256
4257                /* Validate the ddr_buffer_addr and buf_type */
4258                hmm_buffer_record = sh_css_hmm_buffer_record_validate(
4259                    ddr_buffer_addr, buf_type);
4260                if (hmm_buffer_record) {
4261                        /* valid hmm_buffer_record found. Save the kernel_ptr
4262                         * for validation after performing hmm_load.  The
4263                         * vbuf handle and buffer_record can be released.
4264                         */
4265                        kernel_ptr = hmm_buffer_record->kernel_ptr;
4266                        ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &hmm_buffer_record->h_vbuf);
4267                        sh_css_hmm_buffer_record_reset(hmm_buffer_record);
4268                } else {
4269                        IA_CSS_ERROR("hmm_buffer_record not found (0x%x) buf_type(%d)",
4270                                     ddr_buffer_addr, buf_type);
4271                        IA_CSS_LEAVE_ERR(-EINVAL);
4272                        return -EINVAL;
4273                }
4274
4275                hmm_load(ddr_buffer_addr,
4276                         &ddr_buffer,
4277                         sizeof(struct sh_css_hmm_buffer));
4278
4279                /* if the kernel_ptr is 0 or an invalid, return an error.
4280                 * do not access the buffer via the kernal_ptr.
4281                 */
4282                if ((ddr_buffer.kernel_ptr == 0) ||
4283                    (kernel_ptr != HOST_ADDRESS(ddr_buffer.kernel_ptr))) {
4284                        IA_CSS_ERROR("kernel_ptr invalid");
4285                        IA_CSS_ERROR("expected: (0x%llx)", (u64)kernel_ptr);
4286                        IA_CSS_ERROR("actual: (0x%llx)", (u64)HOST_ADDRESS(ddr_buffer.kernel_ptr));
4287                        IA_CSS_ERROR("buf_type: %d\n", buf_type);
4288                        IA_CSS_LEAVE_ERR(-EINVAL);
4289                        return -EINVAL;
4290                }
4291
4292                if (ddr_buffer.kernel_ptr != 0) {
4293                        /* buffer->exp_id : all instances to be removed later once the driver change
4294                         * is completed. See patch #5758 for reference */
4295                        buffer->exp_id = 0;
4296                        buffer->driver_cookie = ddr_buffer.cookie_ptr;
4297                        buffer->timing_data = ddr_buffer.timing_data;
4298
4299                        if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
4300                            buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
4301                                buffer->isys_eof_clock_tick.ticks = ddr_buffer.isys_eof_clock_tick;
4302                        }
4303
4304                        switch (buf_type) {
4305                        case IA_CSS_BUFFER_TYPE_INPUT_FRAME:
4306                        case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
4307                        case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
4308                                if (pipe && pipe->stop_requested) {
4309#if !defined(ISP2401)
4310                                        /* free mipi frames only for old input system
4311                                         * for 2401 it is done in ia_css_stream_destroy call
4312                                         */
4313                                        return_err = free_mipi_frames(pipe);
4314                                        if (return_err) {
4315                                                IA_CSS_LOG("free_mipi_frames() failed");
4316                                                IA_CSS_LEAVE_ERR(return_err);
4317                                                return return_err;
4318                                        }
4319#endif
4320                                        pipe->stop_requested = false;
4321                                }
4322                                fallthrough;
4323                        case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
4324                        case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
4325                                frame = (struct ia_css_frame *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4326                                buffer->data.frame = frame;
4327                                buffer->exp_id = ddr_buffer.payload.frame.exp_id;
4328                                frame->exp_id = ddr_buffer.payload.frame.exp_id;
4329                                frame->isp_config_id = ddr_buffer.payload.frame.isp_parameters_id;
4330                                if (ddr_buffer.payload.frame.flashed == 1)
4331                                        frame->flash_state =
4332                                            IA_CSS_FRAME_FLASH_STATE_PARTIAL;
4333                                if (ddr_buffer.payload.frame.flashed == 2)
4334                                        frame->flash_state =
4335                                            IA_CSS_FRAME_FLASH_STATE_FULL;
4336                                frame->valid = pipe->num_invalid_frames == 0;
4337                                if (!frame->valid)
4338                                        pipe->num_invalid_frames--;
4339
4340                                if (frame->info.format == IA_CSS_FRAME_FORMAT_BINARY_8) {
4341#ifdef ISP2401
4342                                        frame->planes.binary.size = frame->data_bytes;
4343#else
4344                                        frame->planes.binary.size =
4345                                            sh_css_sp_get_binary_copy_size();
4346#endif
4347                                }
4348#if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS)
4349                                if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
4350                                        IA_CSS_LOG("pfp: dequeued OF %d with config id %d thread %d",
4351                                                   frame->data, frame->isp_config_id, thread_id);
4352                                }
4353#endif
4354
4355                                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4356                                                    "ia_css_pipe_dequeue_buffer() buf_type=%d, data(DDR address)=0x%x\n",
4357                                                    buf_type, buffer->data.frame->data);
4358
4359                                break;
4360                        case IA_CSS_BUFFER_TYPE_3A_STATISTICS:
4361                                buffer->data.stats_3a =
4362                                    (struct ia_css_isp_3a_statistics *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4363                                buffer->exp_id = ddr_buffer.payload.s3a.exp_id;
4364                                buffer->data.stats_3a->exp_id = ddr_buffer.payload.s3a.exp_id;
4365                                buffer->data.stats_3a->isp_config_id = ddr_buffer.payload.s3a.isp_config_id;
4366                                break;
4367                        case IA_CSS_BUFFER_TYPE_DIS_STATISTICS:
4368                                buffer->data.stats_dvs =
4369                                    (struct ia_css_isp_dvs_statistics *)
4370                                    HOST_ADDRESS(ddr_buffer.kernel_ptr);
4371                                buffer->exp_id = ddr_buffer.payload.dis.exp_id;
4372                                buffer->data.stats_dvs->exp_id = ddr_buffer.payload.dis.exp_id;
4373                                break;
4374                        case IA_CSS_BUFFER_TYPE_LACE_STATISTICS:
4375                                break;
4376                        case IA_CSS_BUFFER_TYPE_METADATA:
4377                                buffer->data.metadata =
4378                                    (struct ia_css_metadata *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4379                                buffer->exp_id = ddr_buffer.payload.metadata.exp_id;
4380                                buffer->data.metadata->exp_id = ddr_buffer.payload.metadata.exp_id;
4381                                break;
4382                        default:
4383                                return_err = -EINVAL;
4384                                break;
4385                        }
4386                }
4387        }
4388
4389        /*
4390         * Tell the SP which queues are not full,
4391         * by sending the software event.
4392         */
4393        if (!return_err) {
4394                if (!sh_css_sp_is_running()) {
4395                        IA_CSS_LOG("SP is not running!");
4396                        IA_CSS_LEAVE_ERR(-EBUSY);
4397                        /* SP is not running. The queues are not valid */
4398                        return -EBUSY;
4399                }
4400                ia_css_bufq_enqueue_psys_event(
4401                    IA_CSS_PSYS_SW_EVENT_BUFFER_DEQUEUED,
4402                    0,
4403                    queue_id,
4404                    0);
4405        }
4406        IA_CSS_LEAVE("buffer=%p", buffer);
4407
4408        return return_err;
4409}
4410
4411/*
4412 * Cannot Move this to event module as it is of ia_css_event_type which is declared in ia_css.h
4413 * TODO: modify and move it if possible.
4414 *
4415 * !!!IMPORTANT!!! KEEP THE FOLLOWING IN SYNC:
4416 * 1) "enum ia_css_event_type"                                  (ia_css_event_public.h)
4417 * 2) "enum sh_css_sp_event_type"                               (sh_css_internal.h)
4418 * 3) "enum ia_css_event_type event_id_2_event_mask"            (event_handler.sp.c)
4419 * 4) "enum ia_css_event_type convert_event_sp_to_host_domain"  (sh_css.c)
4420 */
4421static enum ia_css_event_type convert_event_sp_to_host_domain[] = {
4422        IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE,    /** Output frame ready. */
4423        IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE,     /** Second output frame ready. */
4424        IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE, /** Viewfinder Output frame ready. */
4425        IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE,  /** Second viewfinder Output frame ready. */
4426        IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE,   /** Indication that 3A statistics are available. */
4427        IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE,  /** Indication that DIS statistics are available. */
4428        IA_CSS_EVENT_TYPE_PIPELINE_DONE,        /** Pipeline Done event, sent after last pipeline stage. */
4429        IA_CSS_EVENT_TYPE_FRAME_TAGGED,         /** Frame tagged. */
4430        IA_CSS_EVENT_TYPE_INPUT_FRAME_DONE,     /** Input frame ready. */
4431        IA_CSS_EVENT_TYPE_METADATA_DONE,        /** Metadata ready. */
4432        IA_CSS_EVENT_TYPE_LACE_STATISTICS_DONE, /** Indication that LACE statistics are available. */
4433        IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE,   /** Extension stage executed. */
4434        IA_CSS_EVENT_TYPE_TIMER,                /** Timing measurement data. */
4435        IA_CSS_EVENT_TYPE_PORT_EOF,             /** End Of Frame event, sent when in buffered sensor mode. */
4436        IA_CSS_EVENT_TYPE_FW_WARNING,           /** Performance warning encountered by FW */
4437        IA_CSS_EVENT_TYPE_FW_ASSERT,            /** Assertion hit by FW */
4438        0,                                      /* error if sp passes  SH_CSS_SP_EVENT_NR_OF_TYPES as a valid event. */
4439};
4440
4441int
4442ia_css_dequeue_event(struct ia_css_event *event)
4443{
4444        return ia_css_dequeue_psys_event(event);
4445}
4446
4447int
4448ia_css_dequeue_psys_event(struct ia_css_event *event)
4449{
4450        enum ia_css_pipe_id pipe_id = 0;
4451        u8 payload[4] = {0, 0, 0, 0};
4452        int ret_err;
4453
4454        /*TODO:
4455         * a) use generic decoding function , same as the one used by sp.
4456         * b) group decode and dequeue into eventQueue module
4457         *
4458         * We skip the IA_CSS_ENTER logging call
4459         * to avoid flooding the logs when the host application
4460         * uses polling. */
4461        if (!event)
4462                return -EINVAL;
4463
4464        /* SP is not running. The queues are not valid */
4465        if (!sh_css_sp_is_running())
4466                return -EBUSY;
4467
4468        /* dequeue the event (if any) from the psys event queue */
4469        ret_err = ia_css_bufq_dequeue_psys_event(payload);
4470        if (ret_err)
4471                return ret_err;
4472
4473        IA_CSS_LOG("event dequeued from psys event queue");
4474
4475        /* Tell the SP that we dequeued an event from the event queue. */
4476        ia_css_bufq_enqueue_psys_event(
4477            IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0);
4478
4479        /* Events are decoded into 4 bytes of payload, the first byte
4480         * contains the sp event type. This is converted to a host enum.
4481         * TODO: can this enum conversion be eliminated */
4482        event->type = convert_event_sp_to_host_domain[payload[0]];
4483        /* Some sane default values since not all events use all fields. */
4484        event->pipe = NULL;
4485        event->port = MIPI_PORT0_ID;
4486        event->exp_id = 0;
4487        event->fw_warning = IA_CSS_FW_WARNING_NONE;
4488        event->fw_handle = 0;
4489        event->timer_data = 0;
4490        event->timer_code = 0;
4491        event->timer_subcode = 0;
4492
4493        if (event->type == IA_CSS_EVENT_TYPE_TIMER) {
4494                /* timer event ??? get the 2nd event and decode the data into the event struct */
4495                u32 tmp_data;
4496                /* 1st event: LSB 16-bit timer data and code */
4497                event->timer_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8));
4498                event->timer_code = payload[2];
4499                payload[0] = payload[1] = payload[2] = payload[3] = 0;
4500                ret_err = ia_css_bufq_dequeue_psys_event(payload);
4501                if (ret_err) {
4502                        /* no 2nd event ??? an error */
4503                        /* Putting IA_CSS_ERROR is resulting in failures in
4504                         * Merrifield smoke testing  */
4505                        IA_CSS_WARNING("Timer: Error de-queuing the 2nd TIMER event!!!\n");
4506                        return ret_err;
4507                }
4508                ia_css_bufq_enqueue_psys_event(
4509                    IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0);
4510                event->type = convert_event_sp_to_host_domain[payload[0]];
4511                /* It's a timer */
4512                if (event->type == IA_CSS_EVENT_TYPE_TIMER) {
4513                        /* 2nd event data: MSB 16-bit timer and subcode */
4514                        tmp_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8));
4515                        event->timer_data |= (tmp_data << 16);
4516                        event->timer_subcode = payload[2];
4517                } else {
4518                /* It's a non timer event. So clear first half of the timer event data.
4519                * If the second part of the TIMER event is not received, we discard
4520                * the first half of the timer data and process the non timer event without
4521                * affecting the flow. So the non timer event falls through
4522                * the code. */
4523                        event->timer_data = 0;
4524                        event->timer_code = 0;
4525                        event->timer_subcode = 0;
4526                        IA_CSS_ERROR("Missing 2nd timer event. Timer event discarded");
4527                }
4528        }
4529        if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF) {
4530                event->port = (enum mipi_port_id)payload[1];
4531                event->exp_id = payload[3];
4532        } else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING) {
4533                event->fw_warning = (enum ia_css_fw_warning)payload[1];
4534                /* exp_id is only available in these warning types */
4535                if (event->fw_warning == IA_CSS_FW_WARNING_EXP_ID_LOCKED ||
4536                    event->fw_warning == IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED)
4537                        event->exp_id = payload[3];
4538        } else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT) {
4539                event->fw_assert_module_id = payload[1]; /* module */
4540                event->fw_assert_line_no = (payload[2] << 8) + payload[3];
4541                /* payload[2] is line_no>>8, payload[3] is line_no&0xff */
4542        } else if (event->type != IA_CSS_EVENT_TYPE_TIMER) {
4543                /* pipe related events.
4544                 * payload[1] contains the pipe_num,
4545                 * payload[2] contains the pipe_id. These are different. */
4546                event->pipe = find_pipe_by_num(payload[1]);
4547                pipe_id = (enum ia_css_pipe_id)payload[2];
4548                /* Check to see if pipe still exists */
4549                if (!event->pipe)
4550                        return -EBUSY;
4551
4552                if (event->type == IA_CSS_EVENT_TYPE_FRAME_TAGGED) {
4553                        /* find the capture pipe that goes with this */
4554                        int i, n;
4555
4556                        n = event->pipe->stream->num_pipes;
4557                        for (i = 0; i < n; i++) {
4558                                struct ia_css_pipe *p =
4559                                            event->pipe->stream->pipes[i];
4560                                if (p->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
4561                                        event->pipe = p;
4562                                        break;
4563                                }
4564                        }
4565                        event->exp_id = payload[3];
4566                }
4567                if (event->type == IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE) {
4568                        /* payload[3] contains the acc fw handle. */
4569                        u32 stage_num = (uint32_t)payload[3];
4570
4571                        ret_err = ia_css_pipeline_get_fw_from_stage(
4572                                      &event->pipe->pipeline,
4573                                      stage_num,
4574                                      &event->fw_handle);
4575                        if (ret_err) {
4576                                IA_CSS_ERROR("Invalid stage num received for ACC event. stage_num:%u",
4577                                             stage_num);
4578                                return ret_err;
4579                        }
4580                }
4581        }
4582
4583        if (event->pipe)
4584                IA_CSS_LEAVE("event_id=%d, pipe_id=%d", event->type, pipe_id);
4585        else
4586                IA_CSS_LEAVE("event_id=%d", event->type);
4587
4588        return 0;
4589}
4590
4591int
4592ia_css_dequeue_isys_event(struct ia_css_event *event)
4593{
4594        u8 payload[4] = {0, 0, 0, 0};
4595        int err = 0;
4596
4597        /* We skip the IA_CSS_ENTER logging call
4598         * to avoid flooding the logs when the host application
4599         * uses polling. */
4600        if (!event)
4601                return -EINVAL;
4602
4603        /* SP is not running. The queues are not valid */
4604        if (!sh_css_sp_is_running())
4605                return -EBUSY;
4606
4607        err = ia_css_bufq_dequeue_isys_event(payload);
4608        if (err)
4609                return err;
4610
4611        IA_CSS_LOG("event dequeued from isys event queue");
4612
4613        /* Update SP state to indicate that element was dequeued. */
4614        ia_css_bufq_enqueue_isys_event(IA_CSS_ISYS_SW_EVENT_EVENT_DEQUEUED);
4615
4616        /* Fill return struct with appropriate info */
4617        event->type = IA_CSS_EVENT_TYPE_PORT_EOF;
4618        /* EOF events are associated with a CSI port, not with a pipe */
4619        event->pipe = NULL;
4620        event->port = payload[1];
4621        event->exp_id = payload[3];
4622
4623        IA_CSS_LEAVE_ERR(err);
4624        return err;
4625}
4626
4627static void
4628acc_start(struct ia_css_pipe *pipe)
4629{
4630        assert(pipe);
4631        assert(pipe->stream);
4632
4633        start_pipe(pipe, SH_CSS_PIPE_CONFIG_OVRD_NO_OVRD,
4634                   pipe->stream->config.mode);
4635}
4636
4637static int
4638sh_css_pipe_start(struct ia_css_stream *stream)
4639{
4640        int err = 0;
4641
4642        struct ia_css_pipe *pipe;
4643        enum ia_css_pipe_id pipe_id;
4644        unsigned int thread_id;
4645
4646        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
4647
4648        if (!stream) {
4649                IA_CSS_LEAVE_ERR(-EINVAL);
4650                return -EINVAL;
4651        }
4652        pipe = stream->last_pipe;
4653        if (!pipe) {
4654                IA_CSS_LEAVE_ERR(-EINVAL);
4655                return -EINVAL;
4656        }
4657
4658        pipe_id = pipe->mode;
4659
4660        if (stream->started) {
4661                IA_CSS_WARNING("Cannot start stream that is already started");
4662                IA_CSS_LEAVE_ERR(err);
4663                return err;
4664        }
4665
4666        pipe->stop_requested = false;
4667
4668        switch (pipe_id) {
4669        case IA_CSS_PIPE_ID_PREVIEW:
4670                err = preview_start(pipe);
4671                break;
4672        case IA_CSS_PIPE_ID_VIDEO:
4673                err = video_start(pipe);
4674                break;
4675        case IA_CSS_PIPE_ID_CAPTURE:
4676                err = capture_start(pipe);
4677                break;
4678        case IA_CSS_PIPE_ID_YUVPP:
4679                err = yuvpp_start(pipe);
4680                break;
4681        case IA_CSS_PIPE_ID_ACC:
4682                acc_start(pipe);
4683                break;
4684        default:
4685                err = -EINVAL;
4686        }
4687        /* DH regular multi pipe - not continuous mode: start the next pipes too */
4688        if (!stream->config.continuous) {
4689                int i;
4690
4691                for (i = 1; i < stream->num_pipes && 0 == err ; i++) {
4692                        switch (stream->pipes[i]->mode) {
4693                        case IA_CSS_PIPE_ID_PREVIEW:
4694                                stream->pipes[i]->stop_requested = false;
4695                                err = preview_start(stream->pipes[i]);
4696                                break;
4697                        case IA_CSS_PIPE_ID_VIDEO:
4698                                stream->pipes[i]->stop_requested = false;
4699                                err = video_start(stream->pipes[i]);
4700                                break;
4701                        case IA_CSS_PIPE_ID_CAPTURE:
4702                                stream->pipes[i]->stop_requested = false;
4703                                err = capture_start(stream->pipes[i]);
4704                                break;
4705                        case IA_CSS_PIPE_ID_YUVPP:
4706                                stream->pipes[i]->stop_requested = false;
4707                                err = yuvpp_start(stream->pipes[i]);
4708                                break;
4709                        case IA_CSS_PIPE_ID_ACC:
4710                                stream->pipes[i]->stop_requested = false;
4711                                acc_start(stream->pipes[i]);
4712                                break;
4713                        default:
4714                                err = -EINVAL;
4715                        }
4716                }
4717        }
4718        if (err) {
4719                IA_CSS_LEAVE_ERR_PRIVATE(err);
4720                return err;
4721        }
4722
4723        /* Force ISP parameter calculation after a mode change
4724         * Acceleration API examples pass NULL for stream but they
4725         * don't use ISP parameters anyway. So this should be okay.
4726         * The SP binary (jpeg) copy does not use any parameters.
4727         */
4728        if (!copy_on_sp(pipe)) {
4729                sh_css_invalidate_params(stream);
4730                err = sh_css_param_update_isp_params(pipe,
4731                                                     stream->isp_params_configs, true, NULL);
4732                if (err) {
4733                        IA_CSS_LEAVE_ERR_PRIVATE(err);
4734                        return err;
4735                }
4736        }
4737
4738        ia_css_debug_pipe_graph_dump_epilogue();
4739
4740        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4741
4742        if (!sh_css_sp_is_running()) {
4743                IA_CSS_LEAVE_ERR_PRIVATE(-EBUSY);
4744                /* SP is not running. The queues are not valid */
4745                return -EBUSY;
4746        }
4747        ia_css_bufq_enqueue_psys_event(IA_CSS_PSYS_SW_EVENT_START_STREAM,
4748                                       (uint8_t)thread_id, 0, 0);
4749
4750        /* DH regular multi pipe - not continuous mode: enqueue event to the next pipes too */
4751        if (!stream->config.continuous) {
4752                int i;
4753
4754                for (i = 1; i < stream->num_pipes; i++) {
4755                        ia_css_pipeline_get_sp_thread_id(
4756                            ia_css_pipe_get_pipe_num(stream->pipes[i]),
4757                            &thread_id);
4758                        ia_css_bufq_enqueue_psys_event(
4759                            IA_CSS_PSYS_SW_EVENT_START_STREAM,
4760                            (uint8_t)thread_id, 0, 0);
4761                }
4762        }
4763
4764        /* in case of continuous capture mode, we also start capture thread and copy thread*/
4765        if (pipe->stream->config.continuous) {
4766                struct ia_css_pipe *copy_pipe = NULL;
4767
4768                if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4769                        copy_pipe = pipe->pipe_settings.preview.copy_pipe;
4770                else if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
4771                        copy_pipe = pipe->pipe_settings.video.copy_pipe;
4772
4773                if (!copy_pipe) {
4774                        IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4775                        return -EINVAL;
4776                }
4777                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(copy_pipe),
4778                                                 &thread_id);
4779                /* by the time we reach here q is initialized and handle is available.*/
4780                ia_css_bufq_enqueue_psys_event(
4781                    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4782                    (uint8_t)thread_id, 0,  0);
4783        }
4784        if (pipe->stream->cont_capt) {
4785                struct ia_css_pipe *capture_pipe = NULL;
4786
4787                if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4788                        capture_pipe = pipe->pipe_settings.preview.capture_pipe;
4789                else if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
4790                        capture_pipe = pipe->pipe_settings.video.capture_pipe;
4791
4792                if (!capture_pipe) {
4793                        IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4794                        return -EINVAL;
4795                }
4796                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
4797                                                 &thread_id);
4798                /* by the time we reach here q is initialized and handle is available.*/
4799                ia_css_bufq_enqueue_psys_event(
4800                    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4801                    (uint8_t)thread_id, 0,  0);
4802        }
4803
4804        /* in case of PREVIEW mode, check whether QOS acc_pipe is available, then start the qos pipe */
4805        if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
4806                struct ia_css_pipe *acc_pipe = NULL;
4807
4808                acc_pipe = pipe->pipe_settings.preview.acc_pipe;
4809
4810                if (acc_pipe) {
4811                        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(acc_pipe),
4812                                                         &thread_id);
4813                        /* by the time we reach here q is initialized and handle is available.*/
4814                        ia_css_bufq_enqueue_psys_event(
4815                            IA_CSS_PSYS_SW_EVENT_START_STREAM,
4816                            (uint8_t)thread_id, 0, 0);
4817                }
4818        }
4819
4820        stream->started = true;
4821
4822        IA_CSS_LEAVE_ERR_PRIVATE(err);
4823        return err;
4824}
4825
4826/* ISP2400 */
4827void
4828sh_css_enable_cont_capt(bool enable, bool stop_copy_preview)
4829{
4830        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4831                            "sh_css_enable_cont_capt() enter: enable=%d\n", enable);
4832//my_css.cont_capt = enable;
4833        my_css.stop_copy_preview = stop_copy_preview;
4834}
4835
4836bool
4837sh_css_continuous_is_enabled(uint8_t pipe_num)
4838{
4839        struct ia_css_pipe *pipe;
4840        bool continuous;
4841
4842        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4843                            "sh_css_continuous_is_enabled() enter: pipe_num=%d\n", pipe_num);
4844
4845        pipe = find_pipe_by_num(pipe_num);
4846        continuous = pipe && pipe->stream->config.continuous;
4847        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4848                            "sh_css_continuous_is_enabled() leave: enable=%d\n",
4849                            continuous);
4850        return continuous;
4851}
4852
4853/* ISP2400 */
4854int
4855ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream,
4856                                   int *buffer_depth)
4857{
4858        if (!buffer_depth)
4859                return -EINVAL;
4860        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_max_buffer_depth() enter: void\n");
4861        (void)stream;
4862        *buffer_depth = NUM_CONTINUOUS_FRAMES;
4863        return 0;
4864}
4865
4866int
4867ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth)
4868{
4869        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_set_buffer_depth() enter: num_frames=%d\n", buffer_depth);
4870        (void)stream;
4871        if (buffer_depth > NUM_CONTINUOUS_FRAMES || buffer_depth < 1)
4872                return -EINVAL;
4873        /* ok, value allowed */
4874        stream->config.target_num_cont_raw_buf = buffer_depth;
4875        /* TODO: check what to regarding initialization */
4876        return 0;
4877}
4878
4879/* ISP2401 */
4880int
4881ia_css_stream_get_buffer_depth(struct ia_css_stream *stream,
4882                               int *buffer_depth)
4883{
4884        if (!buffer_depth)
4885                return -EINVAL;
4886        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_buffer_depth() enter: void\n");
4887        (void)stream;
4888        *buffer_depth = stream->config.target_num_cont_raw_buf;
4889        return 0;
4890}
4891
4892/*
4893 * @brief Stop all "ia_css_pipe" instances in the target
4894 * "ia_css_stream" instance.
4895 *
4896 * Refer to "Local prototypes" for more info.
4897 */
4898/* ISP2401 */
4899static int
4900sh_css_pipes_stop(struct ia_css_stream *stream)
4901{
4902        int err = 0;
4903        struct ia_css_pipe *main_pipe;
4904        enum ia_css_pipe_id main_pipe_id;
4905        int i;
4906
4907        if (!stream) {
4908                IA_CSS_LOG("stream does NOT exist!");
4909                err = -EINVAL;
4910                goto ERR;
4911        }
4912
4913        main_pipe = stream->last_pipe;
4914        if (!main_pipe) {
4915                IA_CSS_LOG("main_pipe does NOT exist!");
4916                err = -EINVAL;
4917                goto ERR;
4918        }
4919
4920        main_pipe_id = main_pipe->mode;
4921        IA_CSS_ENTER_PRIVATE("main_pipe_id=%d", main_pipe_id);
4922
4923        /*
4924         * Stop all "ia_css_pipe" instances in this target
4925         * "ia_css_stream" instance.
4926         */
4927        for (i = 0; i < stream->num_pipes; i++) {
4928                /* send the "stop" request to the "ia_css_pipe" instance */
4929                IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d",
4930                           stream->pipes[i]->pipeline.pipe_id);
4931                err = ia_css_pipeline_request_stop(&stream->pipes[i]->pipeline);
4932
4933                /*
4934                * Exit this loop if "ia_css_pipeline_request_stop()"
4935                * returns the error code.
4936                *
4937                * The error code would be generated in the following
4938                * two cases:
4939                * (1) The Scalar Processor has already been stopped.
4940                * (2) The "Host->SP" event queue is full.
4941                *
4942                * As the convention of using CSS API 2.0/2.1, such CSS
4943                * error code would be propogated from the CSS-internal
4944                * API returned value to the CSS API returned value. Then
4945                * the CSS driver should capture these error code and
4946                * handle it in the driver exception handling mechanism.
4947                */
4948                if (err)
4949                        goto ERR;
4950        }
4951
4952        /*
4953         * In the CSS firmware use scenario "Continuous Preview"
4954         * as well as "Continuous Video", the "ia_css_pipe" instance
4955         * "Copy Pipe" is activated. This "Copy Pipe" is private to
4956         * the CSS firmware so that it is not listed in the target
4957         * "ia_css_stream" instance.
4958         *
4959         * We need to stop this "Copy Pipe", as well.
4960         */
4961        if (main_pipe->stream->config.continuous) {
4962                struct ia_css_pipe *copy_pipe = NULL;
4963
4964                /* get the reference to "Copy Pipe" */
4965                if (main_pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4966                        copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
4967                else if (main_pipe_id == IA_CSS_PIPE_ID_VIDEO)
4968                        copy_pipe = main_pipe->pipe_settings.video.copy_pipe;
4969
4970                /* return the error code if "Copy Pipe" does NOT exist */
4971                if (!copy_pipe) {
4972                        IA_CSS_LOG("Copy Pipe does NOT exist!");
4973                        err = -EINVAL;
4974                        goto ERR;
4975                }
4976
4977                /* send the "stop" request to "Copy Pipe" */
4978                IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d",
4979                           copy_pipe->pipeline.pipe_id);
4980                err = ia_css_pipeline_request_stop(&copy_pipe->pipeline);
4981        }
4982
4983ERR:
4984        IA_CSS_LEAVE_ERR_PRIVATE(err);
4985        return err;
4986}
4987
4988/*
4989 * @brief Check if all "ia_css_pipe" instances in the target
4990 * "ia_css_stream" instance have stopped.
4991 *
4992 * Refer to "Local prototypes" for more info.
4993 */
4994/* ISP2401 */
4995static bool
4996sh_css_pipes_have_stopped(struct ia_css_stream *stream)
4997{
4998        bool rval = true;
4999
5000        struct ia_css_pipe *main_pipe;
5001        enum ia_css_pipe_id main_pipe_id;
5002
5003        int i;
5004
5005        if (!stream) {
5006                IA_CSS_LOG("stream does NOT exist!");
5007                rval = false;
5008                goto RET;
5009        }
5010
5011        main_pipe = stream->last_pipe;
5012
5013        if (!main_pipe) {
5014                IA_CSS_LOG("main_pipe does NOT exist!");
5015                rval = false;
5016                goto RET;
5017        }
5018
5019        main_pipe_id = main_pipe->mode;
5020        IA_CSS_ENTER_PRIVATE("main_pipe_id=%d", main_pipe_id);
5021
5022        /*
5023         * Check if every "ia_css_pipe" instance in this target
5024         * "ia_css_stream" instance has stopped.
5025         */
5026        for (i = 0; i < stream->num_pipes; i++) {
5027                rval = rval && ia_css_pipeline_has_stopped(&stream->pipes[i]->pipeline);
5028                IA_CSS_LOG("Pipe has stopped: pipe_id=%d, stopped=%d",
5029                           stream->pipes[i]->pipeline.pipe_id,
5030                           rval);
5031        }
5032
5033        /*
5034         * In the CSS firmware use scenario "Continuous Preview"
5035         * as well as "Continuous Video", the "ia_css_pipe" instance
5036         * "Copy Pipe" is activated. This "Copy Pipe" is private to
5037         * the CSS firmware so that it is not listed in the target
5038         * "ia_css_stream" instance.
5039         *
5040         * We need to check if this "Copy Pipe" has stopped, as well.
5041         */
5042        if (main_pipe->stream->config.continuous) {
5043                struct ia_css_pipe *copy_pipe = NULL;
5044
5045                /* get the reference to "Copy Pipe" */
5046                if (main_pipe_id == IA_CSS_PIPE_ID_PREVIEW)
5047                        copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
5048                else if (main_pipe_id == IA_CSS_PIPE_ID_VIDEO)
5049                        copy_pipe = main_pipe->pipe_settings.video.copy_pipe;
5050
5051                /* return if "Copy Pipe" does NOT exist */
5052                if (!copy_pipe) {
5053                        IA_CSS_LOG("Copy Pipe does NOT exist!");
5054
5055                        rval = false;
5056                        goto RET;
5057                }
5058
5059                /* check if "Copy Pipe" has stopped or not */
5060                rval = rval && ia_css_pipeline_has_stopped(&copy_pipe->pipeline);
5061                IA_CSS_LOG("Pipe has stopped: pipe_id=%d, stopped=%d",
5062                           copy_pipe->pipeline.pipe_id,
5063                           rval);
5064        }
5065
5066RET:
5067        IA_CSS_LEAVE_PRIVATE("rval=%d", rval);
5068        return rval;
5069}
5070
5071#if !defined(ISP2401)
5072unsigned int
5073sh_css_get_mipi_sizes_for_check(const unsigned int port, const unsigned int idx)
5074{
5075        OP___assert(port < N_CSI_PORTS);
5076        OP___assert(idx  < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT);
5077        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5078                            "sh_css_get_mipi_sizes_for_check(port %d, idx %d): %d\n",
5079                            port, idx, my_css.mipi_sizes_for_check[port][idx]);
5080        return my_css.mipi_sizes_for_check[port][idx];
5081}
5082#endif
5083
5084static int sh_css_pipe_configure_output(
5085    struct ia_css_pipe *pipe,
5086    unsigned int width,
5087    unsigned int height,
5088    unsigned int padded_width,
5089    enum ia_css_frame_format format,
5090    unsigned int idx)
5091{
5092        int err = 0;
5093
5094        IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, padded width = %d, format = %d, idx = %d",
5095                             pipe, width, height, padded_width, format, idx);
5096        if (!pipe) {
5097                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5098                return -EINVAL;
5099        }
5100
5101        err = ia_css_util_check_res(width, height);
5102        if (err) {
5103                IA_CSS_LEAVE_ERR_PRIVATE(err);
5104                return err;
5105        }
5106        if (pipe->output_info[idx].res.width != width ||
5107            pipe->output_info[idx].res.height != height ||
5108            pipe->output_info[idx].format != format) {
5109                ia_css_frame_info_init(
5110                    &pipe->output_info[idx],
5111                    width,
5112                    height,
5113                    format,
5114                    padded_width);
5115        }
5116        IA_CSS_LEAVE_ERR_PRIVATE(0);
5117        return 0;
5118}
5119
5120static int
5121sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe,
5122                             struct ia_css_shading_info *shading_info,
5123                             struct ia_css_pipe_config *pipe_config)
5124{
5125        int err = 0;
5126        struct ia_css_binary *binary = NULL;
5127
5128        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5129                            "sh_css_pipe_get_shading_info() enter:\n");
5130
5131        binary = ia_css_pipe_get_shading_correction_binary(pipe);
5132
5133        if (binary) {
5134                err = ia_css_binary_get_shading_info(binary,
5135                                                     IA_CSS_SHADING_CORRECTION_TYPE_1,
5136                                                     pipe->required_bds_factor,
5137                                                     (const struct ia_css_stream_config *)&pipe->stream->config,
5138                                                     shading_info, pipe_config);
5139
5140                /* Other function calls can be added here when other shading correction types will be added
5141                 * in the future.
5142                 */
5143        } else {
5144                /* When the pipe does not have a binary which has the shading
5145                 * correction, this function does not need to fill the shading
5146                 * information. It is not a error case, and then
5147                 * this function should return 0.
5148                 */
5149                memset(shading_info, 0, sizeof(*shading_info));
5150        }
5151        return err;
5152}
5153
5154static int
5155sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe,
5156                          struct ia_css_grid_info *info)
5157{
5158        int err = 0;
5159        struct ia_css_binary *binary = NULL;
5160
5161        assert(pipe);
5162        assert(info);
5163
5164        IA_CSS_ENTER_PRIVATE("");
5165
5166        binary = ia_css_pipe_get_s3a_binary(pipe);
5167
5168        if (binary) {
5169                err = ia_css_binary_3a_grid_info(binary, info, pipe);
5170                if (err)
5171                        goto err;
5172        } else {
5173                memset(&info->s3a_grid, 0, sizeof(info->s3a_grid));
5174        }
5175
5176        binary = ia_css_pipe_get_sdis_binary(pipe);
5177
5178        if (binary) {
5179                ia_css_binary_dvs_grid_info(binary, info, pipe);
5180                ia_css_binary_dvs_stat_grid_info(binary, info, pipe);
5181        } else {
5182                memset(&info->dvs_grid, 0, sizeof(info->dvs_grid));
5183        }
5184
5185        if (binary) {
5186                /* copy pipe does not have ISP binary*/
5187                info->isp_in_width = binary->internal_frame_info.res.width;
5188                info->isp_in_height = binary->internal_frame_info.res.height;
5189        }
5190
5191        info->vamem_type = IA_CSS_VAMEM_TYPE_2;
5192
5193err:
5194        IA_CSS_LEAVE_ERR_PRIVATE(err);
5195        return err;
5196}
5197
5198/* ISP2401 */
5199/*
5200 * @brief Check if a format is supported by the pipe.
5201 *
5202 */
5203static int
5204ia_css_pipe_check_format(struct ia_css_pipe *pipe,
5205                         enum ia_css_frame_format format)
5206{
5207        const enum ia_css_frame_format *supported_formats;
5208        int number_of_formats;
5209        int found = 0;
5210        int i;
5211
5212        IA_CSS_ENTER_PRIVATE("");
5213
5214        if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info) {
5215                IA_CSS_ERROR("Pipe or binary info is not set");
5216                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5217                return -EINVAL;
5218        }
5219
5220        supported_formats = pipe->pipe_settings.video.video_binary.info->output_formats;
5221        number_of_formats = sizeof(pipe->pipe_settings.video.video_binary.info->output_formats) / sizeof(enum ia_css_frame_format);
5222
5223        for (i = 0; i < number_of_formats && !found; i++) {
5224                if (supported_formats[i] == format) {
5225                        found = 1;
5226                        break;
5227                }
5228        }
5229        if (!found) {
5230                IA_CSS_ERROR("Requested format is not supported by binary");
5231                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5232                return -EINVAL;
5233        }
5234        IA_CSS_LEAVE_ERR_PRIVATE(0);
5235        return 0;
5236}
5237
5238static int load_video_binaries(struct ia_css_pipe *pipe)
5239{
5240        struct ia_css_frame_info video_in_info, tnr_info,
5241                       *video_vf_info, video_bds_out_info, *pipe_out_info, *pipe_vf_out_info;
5242        bool online;
5243        int err = 0;
5244        bool continuous = pipe->stream->config.continuous;
5245        unsigned int i;
5246        unsigned int num_output_pins;
5247        struct ia_css_frame_info video_bin_out_info;
5248        bool need_scaler = false;
5249        bool vf_res_different_than_output = false;
5250        bool need_vf_pp = false;
5251        int vf_ds_log2;
5252        struct ia_css_video_settings *mycs  = &pipe->pipe_settings.video;
5253
5254        IA_CSS_ENTER_PRIVATE("");
5255        assert(pipe);
5256        assert(pipe->mode == IA_CSS_PIPE_ID_VIDEO);
5257        /* we only test the video_binary because offline video doesn't need a
5258         * vf_pp binary and online does not (always use) the copy_binary.
5259         * All are always reset at the same time anyway.
5260         */
5261        if (mycs->video_binary.info)
5262                return 0;
5263
5264        online = pipe->stream->config.online;
5265        pipe_out_info = &pipe->output_info[0];
5266        pipe_vf_out_info = &pipe->vf_output_info[0];
5267
5268        assert(pipe_out_info);
5269
5270        /*
5271         * There is no explicit input format requirement for raw or yuv
5272         * What matters is that there is a binary that supports the stream format.
5273         * This is checked in the binary_find(), so no need to check it here
5274         */
5275        err = ia_css_util_check_input(&pipe->stream->config, false, false);
5276        if (err)
5277                return err;
5278        /* cannot have online video and input_mode memory */
5279        if (online && pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY)
5280                return -EINVAL;
5281        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5282                err = ia_css_util_check_vf_out_info(pipe_out_info,
5283                                                    pipe_vf_out_info);
5284                if (err)
5285                        return err;
5286        } else {
5287                err = ia_css_frame_check_info(pipe_out_info);
5288                if (err)
5289                        return err;
5290        }
5291
5292        if (pipe->out_yuv_ds_input_info.res.width)
5293                video_bin_out_info = pipe->out_yuv_ds_input_info;
5294        else
5295                video_bin_out_info = *pipe_out_info;
5296
5297        /* Video */
5298        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5299                video_vf_info = pipe_vf_out_info;
5300                vf_res_different_than_output = (video_vf_info->res.width !=
5301                                                video_bin_out_info.res.width) ||
5302                                               (video_vf_info->res.height != video_bin_out_info.res.height);
5303        } else {
5304                video_vf_info = NULL;
5305        }
5306
5307        need_scaler = need_downscaling(video_bin_out_info.res, pipe_out_info->res);
5308
5309        /* we build up the pipeline starting at the end */
5310        /* YUV post-processing if needed */
5311        if (need_scaler) {
5312                struct ia_css_cas_binary_descr cas_scaler_descr = { };
5313
5314                /* NV12 is the common format that is supported by both */
5315                /* yuv_scaler and the video_xx_isp2_min binaries. */
5316                video_bin_out_info.format = IA_CSS_FRAME_FORMAT_NV12;
5317
5318                err = ia_css_pipe_create_cas_scaler_desc_single_output(
5319                          &video_bin_out_info,
5320                          pipe_out_info,
5321                          NULL,
5322                          &cas_scaler_descr);
5323                if (err)
5324                        return err;
5325                mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
5326                mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage,
5327                                                  sizeof(struct ia_css_binary),
5328                                                  GFP_KERNEL);
5329                if (!mycs->yuv_scaler_binary) {
5330                        err = -ENOMEM;
5331                        return err;
5332                }
5333                mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage,
5334                                                sizeof(bool), GFP_KERNEL);
5335                if (!mycs->is_output_stage) {
5336                        err = -ENOMEM;
5337                        return err;
5338                }
5339                for (i = 0; i < cas_scaler_descr.num_stage; i++) {
5340                        struct ia_css_binary_descr yuv_scaler_descr;
5341
5342                        mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
5343                        ia_css_pipe_get_yuvscaler_binarydesc(pipe,
5344                                                             &yuv_scaler_descr, &cas_scaler_descr.in_info[i],
5345                                                             &cas_scaler_descr.out_info[i],
5346                                                             &cas_scaler_descr.internal_out_info[i],
5347                                                             &cas_scaler_descr.vf_info[i]);
5348                        err = ia_css_binary_find(&yuv_scaler_descr,
5349                                                 &mycs->yuv_scaler_binary[i]);
5350                        if (err) {
5351                                kfree(mycs->is_output_stage);
5352                                mycs->is_output_stage = NULL;
5353                                return err;
5354                        }
5355                }
5356                ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
5357        }
5358
5359        {
5360                struct ia_css_binary_descr video_descr;
5361                enum ia_css_frame_format vf_info_format;
5362
5363                err = ia_css_pipe_get_video_binarydesc(pipe,
5364                                                       &video_descr, &video_in_info, &video_bds_out_info, &video_bin_out_info,
5365                                                       video_vf_info,
5366                                                       pipe->stream->config.left_padding);
5367                if (err)
5368                        return err;
5369
5370                /* In the case where video_vf_info is not NULL, this allows
5371                 * us to find a potential video library with desired vf format.
5372                 * If success, no vf_pp binary is needed.
5373                 * If failed, we will look up video binary with YUV_LINE vf format
5374                 */
5375                err = ia_css_binary_find(&video_descr,
5376                                         &mycs->video_binary);
5377
5378                if (err) {
5379                        /* This will do another video binary lookup later for YUV_LINE format*/
5380                        if (video_vf_info)
5381                                need_vf_pp = true;
5382                        else
5383                                return err;
5384                } else if (video_vf_info) {
5385                        /* The first video binary lookup is successful, but we may
5386                         * still need vf_pp binary based on additiona check */
5387                        num_output_pins = mycs->video_binary.info->num_output_pins;
5388                        vf_ds_log2 = mycs->video_binary.vf_downscale_log2;
5389
5390                        /* If the binary has dual output pins, we need vf_pp if the resolution
5391                        * is different. */
5392                        need_vf_pp |= ((num_output_pins == 2) && vf_res_different_than_output);
5393
5394                        /* If the binary has single output pin, we need vf_pp if additional
5395                        * scaling is needed for vf */
5396                        need_vf_pp |= ((num_output_pins == 1) &&
5397                                       ((video_vf_info->res.width << vf_ds_log2 != pipe_out_info->res.width) ||
5398                                        (video_vf_info->res.height << vf_ds_log2 != pipe_out_info->res.height)));
5399                }
5400
5401                if (need_vf_pp) {
5402                        /* save the current vf_info format for restoration later */
5403                        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
5404                                            "load_video_binaries() need_vf_pp; find video binary with YUV_LINE again\n");
5405
5406                        vf_info_format = video_vf_info->format;
5407
5408                        if (!pipe->config.enable_vfpp_bci)
5409                                ia_css_frame_info_set_format(video_vf_info,
5410                                                             IA_CSS_FRAME_FORMAT_YUV_LINE);
5411
5412                        ia_css_binary_destroy_isp_parameters(&mycs->video_binary);
5413
5414                        err = ia_css_binary_find(&video_descr,
5415                                                 &mycs->video_binary);
5416
5417                        /* restore original vf_info format */
5418                        ia_css_frame_info_set_format(video_vf_info,
5419                                                     vf_info_format);
5420                        if (err)
5421                                return err;
5422                }
5423        }
5424
5425        /* If a video binary does not use a ref_frame, we set the frame delay
5426         * to 0. This is the case for the 1-stage low-power video binary. */
5427        if (!mycs->video_binary.info->sp.enable.ref_frame)
5428                pipe->dvs_frame_delay = 0;
5429
5430        /* The delay latency determines the number of invalid frames after
5431         * a stream is started. */
5432        pipe->num_invalid_frames = pipe->dvs_frame_delay;
5433        pipe->info.num_invalid_frames = pipe->num_invalid_frames;
5434
5435        /* Viewfinder frames also decrement num_invalid_frames. If the pipe
5436         * outputs a viewfinder output, then we need double the number of
5437         * invalid frames */
5438        if (video_vf_info)
5439                pipe->num_invalid_frames *= 2;
5440
5441        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
5442                            "load_video_binaries() num_invalid_frames=%d dvs_frame_delay=%d\n",
5443                            pipe->num_invalid_frames, pipe->dvs_frame_delay);
5444
5445        /* pqiao TODO: temp hack for PO, should be removed after offline YUVPP is enabled */
5446#if !defined(ISP2401)
5447        /* Copy */
5448        if (!online && !continuous) {
5449                /* TODO: what exactly needs doing, prepend the copy binary to
5450                 *       video base this only on !online?
5451                 */
5452                err = load_copy_binary(pipe,
5453                                       &mycs->copy_binary,
5454                                       &mycs->video_binary);
5455                if (err)
5456                        return err;
5457        }
5458#else
5459        (void)continuous;
5460#endif
5461
5462#if !defined(HAS_OUTPUT_SYSTEM)
5463        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] && need_vf_pp) {
5464                struct ia_css_binary_descr vf_pp_descr;
5465
5466                if (mycs->video_binary.vf_frame_info.format
5467                    == IA_CSS_FRAME_FORMAT_YUV_LINE) {
5468                        ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
5469                                                        &mycs->video_binary.vf_frame_info,
5470                                                        pipe_vf_out_info);
5471                } else {
5472                        /* output from main binary is not yuv line. currently this is
5473                         * possible only when bci is enabled on vfpp output */
5474                        assert(pipe->config.enable_vfpp_bci);
5475                        ia_css_pipe_get_yuvscaler_binarydesc(pipe, &vf_pp_descr,
5476                                                             &mycs->video_binary.vf_frame_info,
5477                                                             pipe_vf_out_info, NULL, NULL);
5478                }
5479
5480                err = ia_css_binary_find(&vf_pp_descr,
5481                                         &mycs->vf_pp_binary);
5482                if (err)
5483                        return err;
5484        }
5485#endif
5486
5487        err = allocate_delay_frames(pipe);
5488
5489        if (err)
5490                return err;
5491
5492        if (mycs->video_binary.info->sp.enable.block_output) {
5493                unsigned int tnr_width;
5494                unsigned int tnr_height;
5495
5496                tnr_info = mycs->video_binary.out_frame_info[0];
5497
5498                if (IS_ISP2401) {
5499                        /* Select resolution for TNR. If
5500                        * output_system_in_resolution(GDC_out_resolution) is
5501                        * being used, then select that as it will also be in resolution for
5502                        * TNR. At present, it only make sense for Skycam */
5503                        if (pipe->config.output_system_in_res.width &&
5504                            pipe->config.output_system_in_res.height) {
5505                                tnr_width = pipe->config.output_system_in_res.width;
5506                                tnr_height = pipe->config.output_system_in_res.height;
5507                        } else {
5508                                tnr_width = tnr_info.res.width;
5509                                tnr_height = tnr_info.res.height;
5510                        }
5511
5512                        /* Make tnr reference buffers output block width(in pix) align */
5513                        tnr_info.res.width  = CEIL_MUL(tnr_width,
5514                                                       (mycs->video_binary.info->sp.block.block_width * ISP_NWAY));
5515                        tnr_info.padded_width = tnr_info.res.width;
5516                } else {
5517                        tnr_height = tnr_info.res.height;
5518                }
5519
5520                /* Make tnr reference buffers output block height align */
5521                tnr_info.res.height = CEIL_MUL(tnr_height,
5522                                               mycs->video_binary.info->sp.block.output_block_height);
5523        } else {
5524                tnr_info = mycs->video_binary.internal_frame_info;
5525        }
5526        tnr_info.format = IA_CSS_FRAME_FORMAT_YUV_LINE;
5527        tnr_info.raw_bit_depth = SH_CSS_TNR_BIT_DEPTH;
5528
5529        for (i = 0; i < NUM_TNR_FRAMES; i++) {
5530                if (mycs->tnr_frames[i]) {
5531                        ia_css_frame_free(mycs->tnr_frames[i]);
5532                        mycs->tnr_frames[i] = NULL;
5533                }
5534                err = ia_css_frame_allocate_from_info(
5535                          &mycs->tnr_frames[i],
5536                          &tnr_info);
5537                if (err)
5538                        return err;
5539        }
5540        IA_CSS_LEAVE_PRIVATE("");
5541        return 0;
5542}
5543
5544static int
5545unload_video_binaries(struct ia_css_pipe *pipe)
5546{
5547        unsigned int i;
5548
5549        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
5550
5551        if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
5552                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5553                return -EINVAL;
5554        }
5555        ia_css_binary_unload(&pipe->pipe_settings.video.copy_binary);
5556        ia_css_binary_unload(&pipe->pipe_settings.video.video_binary);
5557        ia_css_binary_unload(&pipe->pipe_settings.video.vf_pp_binary);
5558
5559        for (i = 0; i < pipe->pipe_settings.video.num_yuv_scaler; i++)
5560                ia_css_binary_unload(&pipe->pipe_settings.video.yuv_scaler_binary[i]);
5561
5562        kfree(pipe->pipe_settings.video.is_output_stage);
5563        pipe->pipe_settings.video.is_output_stage = NULL;
5564        kfree(pipe->pipe_settings.video.yuv_scaler_binary);
5565        pipe->pipe_settings.video.yuv_scaler_binary = NULL;
5566
5567        IA_CSS_LEAVE_ERR_PRIVATE(0);
5568        return 0;
5569}
5570
5571static int video_start(struct ia_css_pipe *pipe)
5572{
5573        int err = 0;
5574        struct ia_css_pipe *copy_pipe, *capture_pipe;
5575        enum sh_css_pipe_config_override copy_ovrd;
5576        enum ia_css_input_mode video_pipe_input_mode;
5577
5578        const struct ia_css_coordinate *coord = NULL;
5579        const struct ia_css_isp_parameters *params = NULL;
5580
5581        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
5582        if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
5583                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5584                return -EINVAL;
5585        }
5586
5587        video_pipe_input_mode = pipe->stream->config.mode;
5588
5589        copy_pipe    = pipe->pipe_settings.video.copy_pipe;
5590        capture_pipe = pipe->pipe_settings.video.capture_pipe;
5591
5592        sh_css_metrics_start_frame();
5593
5594        /* multi stream video needs mipi buffers */
5595
5596        err = send_mipi_frames(pipe);
5597        if (err)
5598                return err;
5599
5600        send_raw_frames(pipe);
5601        {
5602                unsigned int thread_id;
5603
5604                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
5605                copy_ovrd = 1 << thread_id;
5606
5607                if (pipe->stream->cont_capt) {
5608                        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
5609                                                         &thread_id);
5610                        copy_ovrd |= 1 << thread_id;
5611                }
5612        }
5613
5614        if (IS_ISP2401) {
5615                coord = &pipe->config.internal_frame_origin_bqs_on_sctbl;
5616                params = pipe->stream->isp_params_configs;
5617        }
5618
5619        /* Construct and load the copy pipe */
5620        if (pipe->stream->config.continuous) {
5621                sh_css_sp_init_pipeline(&copy_pipe->pipeline,
5622                                        IA_CSS_PIPE_ID_COPY,
5623                                        (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
5624                                        false,
5625                                        pipe->stream->config.pixels_per_clock == 2, false,
5626                                        false, pipe->required_bds_factor,
5627                                        copy_ovrd,
5628                                        pipe->stream->config.mode,
5629                                        &pipe->stream->config.metadata_config,
5630                                        &pipe->stream->info.metadata_info,
5631                                        pipe->stream->config.source.port.port,
5632                                        coord,
5633                                        params);
5634
5635                /* make the video pipe start with mem mode input, copy handles
5636                   the actual mode */
5637                video_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY;
5638        }
5639
5640        /* Construct and load the capture pipe */
5641        if (pipe->stream->cont_capt) {
5642                sh_css_sp_init_pipeline(&capture_pipe->pipeline,
5643                                        IA_CSS_PIPE_ID_CAPTURE,
5644                                        (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
5645                                        capture_pipe->config.default_capture_config.enable_xnr != 0,
5646                                        capture_pipe->stream->config.pixels_per_clock == 2,
5647                                        true, /* continuous */
5648                                        false, /* offline */
5649                                        capture_pipe->required_bds_factor,
5650                                        0,
5651                                        IA_CSS_INPUT_MODE_MEMORY,
5652                                        &pipe->stream->config.metadata_config,
5653                                        &pipe->stream->info.metadata_info,
5654                                        (enum mipi_port_id)0,
5655                                        coord,
5656                                        params);
5657        }
5658
5659        start_pipe(pipe, copy_ovrd, video_pipe_input_mode);
5660
5661        IA_CSS_LEAVE_ERR_PRIVATE(err);
5662        return err;
5663}
5664
5665static
5666int sh_css_pipe_get_viewfinder_frame_info(
5667    struct ia_css_pipe *pipe,
5668    struct ia_css_frame_info *info,
5669    unsigned int idx)
5670{
5671        assert(pipe);
5672        assert(info);
5673
5674        /* We could print the pointer as input arg, and the values as output */
5675        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5676                            "sh_css_pipe_get_viewfinder_frame_info() enter: void\n");
5677
5678        if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE &&
5679            (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW ||
5680             pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER))
5681                return -EINVAL;
5682        /* offline video does not generate viewfinder output */
5683        *info = pipe->vf_output_info[idx];
5684
5685        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5686                            "sh_css_pipe_get_viewfinder_frame_info() leave: \
5687                info.res.width=%d, info.res.height=%d, \
5688                info.padded_width=%d, info.format=%d, \
5689                info.raw_bit_depth=%d, info.raw_bayer_order=%d\n",
5690                            info->res.width, info->res.height,
5691                            info->padded_width, info->format,
5692                            info->raw_bit_depth, info->raw_bayer_order);
5693
5694        return 0;
5695}
5696
5697static int
5698sh_css_pipe_configure_viewfinder(struct ia_css_pipe *pipe, unsigned int width,
5699                                 unsigned int height, unsigned int min_width,
5700                                 enum ia_css_frame_format format,
5701                                 unsigned int idx)
5702{
5703        int err = 0;
5704
5705        IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, min_width = %d, format = %d, idx = %d\n",
5706                             pipe, width, height, min_width, format, idx);
5707
5708        if (!pipe) {
5709                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5710                return -EINVAL;
5711        }
5712
5713        err = ia_css_util_check_res(width, height);
5714        if (err) {
5715                IA_CSS_LEAVE_ERR_PRIVATE(err);
5716                return err;
5717        }
5718        if (pipe->vf_output_info[idx].res.width != width ||
5719            pipe->vf_output_info[idx].res.height != height ||
5720            pipe->vf_output_info[idx].format != format)
5721                ia_css_frame_info_init(&pipe->vf_output_info[idx], width, height,
5722                                       format, min_width);
5723
5724        IA_CSS_LEAVE_ERR_PRIVATE(0);
5725        return 0;
5726}
5727
5728static int load_copy_binaries(struct ia_css_pipe *pipe)
5729{
5730        int err = 0;
5731
5732        assert(pipe);
5733        IA_CSS_ENTER_PRIVATE("");
5734
5735        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5736               pipe->mode == IA_CSS_PIPE_ID_COPY);
5737        if (pipe->pipe_settings.capture.copy_binary.info)
5738                return 0;
5739
5740        err = ia_css_frame_check_info(&pipe->output_info[0]);
5741        if (err)
5742                goto ERR;
5743
5744        err = verify_copy_out_frame_format(pipe);
5745        if (err)
5746                goto ERR;
5747
5748        err = load_copy_binary(pipe,
5749                               &pipe->pipe_settings.capture.copy_binary,
5750                               NULL);
5751
5752ERR:
5753        IA_CSS_LEAVE_ERR_PRIVATE(err);
5754        return err;
5755}
5756
5757static bool need_capture_pp(
5758    const struct ia_css_pipe *pipe)
5759{
5760        const struct ia_css_frame_info *out_info = &pipe->output_info[0];
5761
5762        IA_CSS_ENTER_LEAVE_PRIVATE("");
5763        assert(pipe);
5764        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
5765
5766        if (IS_ISP2401) {
5767                /* ldc and capture_pp are not supported in the same pipeline */
5768                if (need_capt_ldc(pipe))
5769                        return false;
5770        }
5771
5772        /* determine whether we need to use the capture_pp binary.
5773         * This is needed for:
5774         *   1. XNR or
5775         *   2. Digital Zoom or
5776         *   3. YUV downscaling
5777         */
5778        if (pipe->out_yuv_ds_input_info.res.width &&
5779            ((pipe->out_yuv_ds_input_info.res.width != out_info->res.width) ||
5780             (pipe->out_yuv_ds_input_info.res.height != out_info->res.height)))
5781                return true;
5782
5783        if (pipe->config.default_capture_config.enable_xnr != 0)
5784                return true;
5785
5786        if ((pipe->stream->isp_params_configs->dz_config.dx < HRT_GDC_N) ||
5787            (pipe->stream->isp_params_configs->dz_config.dy < HRT_GDC_N) ||
5788            pipe->config.enable_dz)
5789                return true;
5790
5791        return false;
5792}
5793
5794static bool need_capt_ldc(
5795    const struct ia_css_pipe *pipe)
5796{
5797        IA_CSS_ENTER_LEAVE_PRIVATE("");
5798        assert(pipe);
5799        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
5800        return (pipe->extra_config.enable_dvs_6axis) ? true : false;
5801}
5802
5803static int set_num_primary_stages(unsigned int *num,
5804                                  enum ia_css_pipe_version version)
5805{
5806        int err = 0;
5807
5808        if (!num)
5809                return -EINVAL;
5810
5811        switch (version) {
5812        case IA_CSS_PIPE_VERSION_2_6_1:
5813                *num = NUM_PRIMARY_HQ_STAGES;
5814                break;
5815        case IA_CSS_PIPE_VERSION_2_2:
5816        case IA_CSS_PIPE_VERSION_1:
5817                *num = NUM_PRIMARY_STAGES;
5818                break;
5819        default:
5820                err = -EINVAL;
5821                break;
5822        }
5823
5824        return err;
5825}
5826
5827static int load_primary_binaries(
5828    struct ia_css_pipe *pipe)
5829{
5830        bool online = false;
5831        bool need_pp = false;
5832        bool need_isp_copy_binary = false;
5833        bool need_ldc = false;
5834#ifdef ISP2401
5835        bool sensor = false;
5836#else
5837        bool memory, continuous;
5838#endif
5839        struct ia_css_frame_info prim_in_info,
5840                       prim_out_info,
5841                       capt_pp_out_info, vf_info,
5842                       *vf_pp_in_info, *pipe_out_info,
5843                       *pipe_vf_out_info, *capt_pp_in_info,
5844                       capt_ldc_out_info;
5845        int err = 0;
5846        struct ia_css_capture_settings *mycs;
5847        unsigned int i;
5848        bool need_extra_yuv_scaler = false;
5849        struct ia_css_binary_descr prim_descr[MAX_NUM_PRIMARY_STAGES];
5850
5851        IA_CSS_ENTER_PRIVATE("");
5852        assert(pipe);
5853        assert(pipe->stream);
5854        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5855               pipe->mode == IA_CSS_PIPE_ID_COPY);
5856
5857        online = pipe->stream->config.online;
5858#ifdef ISP2401
5859        sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
5860#else
5861        memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
5862        continuous = pipe->stream->config.continuous;
5863#endif
5864
5865        mycs = &pipe->pipe_settings.capture;
5866        pipe_out_info = &pipe->output_info[0];
5867        pipe_vf_out_info = &pipe->vf_output_info[0];
5868
5869        if (mycs->primary_binary[0].info)
5870                return 0;
5871
5872        err = set_num_primary_stages(&mycs->num_primary_stage,
5873                                     pipe->config.isp_pipe_version);
5874        if (err) {
5875                IA_CSS_LEAVE_ERR_PRIVATE(err);
5876                return err;
5877        }
5878
5879        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5880                err = ia_css_util_check_vf_out_info(pipe_out_info, pipe_vf_out_info);
5881                if (err) {
5882                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5883                        return err;
5884                }
5885        } else {
5886                err = ia_css_frame_check_info(pipe_out_info);
5887                if (err) {
5888                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5889                        return err;
5890                }
5891        }
5892        need_pp = need_capture_pp(pipe);
5893
5894        /* we use the vf output info to get the primary/capture_pp binary
5895           configured for vf_veceven. It will select the closest downscaling
5896           factor. */
5897        vf_info = *pipe_vf_out_info;
5898
5899        /*
5900         * WARNING: The #if def flag has been added below as a
5901         * temporary solution to solve the problem of enabling the
5902         * view finder in a single binary in a capture flow. The
5903         * vf-pp stage has been removed for Skycam in the solution
5904         * provided. The vf-pp stage should be re-introduced when
5905         * required. This should not be considered as a clean solution.
5906         * Proper investigation should be done to come up with the clean
5907         * solution.
5908         * */
5909        ia_css_frame_info_set_format(&vf_info, IA_CSS_FRAME_FORMAT_YUV_LINE);
5910
5911        /* TODO: All this yuv_scaler and capturepp calculation logic
5912         * can be shared later. Capture_pp is also a yuv_scale binary
5913         * with extra XNR funcionality. Therefore, it can be made as the
5914         * first step of the cascade. */
5915        capt_pp_out_info = pipe->out_yuv_ds_input_info;
5916        capt_pp_out_info.format = IA_CSS_FRAME_FORMAT_YUV420;
5917        capt_pp_out_info.res.width  /= MAX_PREFERRED_YUV_DS_PER_STEP;
5918        capt_pp_out_info.res.height /= MAX_PREFERRED_YUV_DS_PER_STEP;
5919        ia_css_frame_info_set_width(&capt_pp_out_info, capt_pp_out_info.res.width, 0);
5920
5921        need_extra_yuv_scaler = need_downscaling(capt_pp_out_info.res,
5922                                                 pipe_out_info->res);
5923
5924        if (need_extra_yuv_scaler) {
5925                struct ia_css_cas_binary_descr cas_scaler_descr = { };
5926
5927                err = ia_css_pipe_create_cas_scaler_desc_single_output(
5928                          &capt_pp_out_info,
5929                          pipe_out_info,
5930                          NULL,
5931                          &cas_scaler_descr);
5932                if (err) {
5933                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5934                        return err;
5935                }
5936                mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
5937                mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage,
5938                                                  sizeof(struct ia_css_binary),
5939                                                  GFP_KERNEL);
5940                if (!mycs->yuv_scaler_binary) {
5941                        err = -ENOMEM;
5942                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5943                        return err;
5944                }
5945                mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage,
5946                                                sizeof(bool), GFP_KERNEL);
5947                if (!mycs->is_output_stage) {
5948                        err = -ENOMEM;
5949                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5950                        return err;
5951                }
5952                for (i = 0; i < cas_scaler_descr.num_stage; i++) {
5953                        struct ia_css_binary_descr yuv_scaler_descr;
5954
5955                        mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
5956                        ia_css_pipe_get_yuvscaler_binarydesc(pipe,
5957                                                             &yuv_scaler_descr, &cas_scaler_descr.in_info[i],
5958                                                             &cas_scaler_descr.out_info[i],
5959                                                             &cas_scaler_descr.internal_out_info[i],
5960                                                             &cas_scaler_descr.vf_info[i]);
5961                        err = ia_css_binary_find(&yuv_scaler_descr,
5962                                                 &mycs->yuv_scaler_binary[i]);
5963                        if (err) {
5964                                IA_CSS_LEAVE_ERR_PRIVATE(err);
5965                                return err;
5966                        }
5967                }
5968                ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
5969
5970        } else {
5971                capt_pp_out_info = pipe->output_info[0];
5972        }
5973
5974        /* TODO Do we disable ldc for skycam */
5975        need_ldc = need_capt_ldc(pipe);
5976        if (IS_ISP2401 && need_ldc) {
5977                /* ldc and capt_pp are not supported in the same pipeline */
5978                struct ia_css_binary_descr capt_ldc_descr;
5979
5980                ia_css_pipe_get_ldc_binarydesc(pipe,
5981                                               &capt_ldc_descr, &prim_out_info,
5982                                               &capt_pp_out_info);
5983
5984                err = ia_css_binary_find(&capt_ldc_descr,
5985                                         &mycs->capture_ldc_binary);
5986                if (err) {
5987                        IA_CSS_LEAVE_ERR_PRIVATE(err);
5988                        return err;
5989                }
5990                need_pp = false;
5991                need_ldc = false;
5992        }
5993
5994        /* we build up the pipeline starting at the end */
5995        /* Capture post-processing */
5996        if (need_pp) {
5997                struct ia_css_binary_descr capture_pp_descr;
5998
5999                if (!IS_ISP2401)
6000                        capt_pp_in_info = need_ldc ? &capt_ldc_out_info : &prim_out_info;
6001                else
6002                        capt_pp_in_info = &prim_out_info;
6003
6004                ia_css_pipe_get_capturepp_binarydesc(pipe,
6005                                                     &capture_pp_descr,
6006                                                     capt_pp_in_info,
6007                                                     &capt_pp_out_info,
6008                                                     &vf_info);
6009
6010                err = ia_css_binary_find(&capture_pp_descr,
6011                                         &mycs->capture_pp_binary);
6012                if (err) {
6013                        IA_CSS_LEAVE_ERR_PRIVATE(err);
6014                        return err;
6015                }
6016
6017                if (need_ldc) {
6018                        struct ia_css_binary_descr capt_ldc_descr;
6019
6020                        ia_css_pipe_get_ldc_binarydesc(pipe,
6021                                                       &capt_ldc_descr,
6022                                                       &prim_out_info,
6023                                                       &capt_ldc_out_info);
6024
6025                        err = ia_css_binary_find(&capt_ldc_descr,
6026                                                 &mycs->capture_ldc_binary);
6027                        if (err) {
6028                                IA_CSS_LEAVE_ERR_PRIVATE(err);
6029                                return err;
6030                        }
6031                }
6032        } else {
6033                prim_out_info = *pipe_out_info;
6034        }
6035
6036        /* Primary */
6037        for (i = 0; i < mycs->num_primary_stage; i++) {
6038                struct ia_css_frame_info *local_vf_info = NULL;
6039
6040                if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] &&
6041                    (i == mycs->num_primary_stage - 1))
6042                        local_vf_info = &vf_info;
6043                ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i],
6044                                                   &prim_in_info, &prim_out_info,
6045                                                   local_vf_info, i);
6046                err = ia_css_binary_find(&prim_descr[i], &mycs->primary_binary[i]);
6047                if (err) {
6048                        IA_CSS_LEAVE_ERR_PRIVATE(err);
6049                        return err;
6050                }
6051        }
6052
6053        /* Viewfinder post-processing */
6054        if (need_pp)
6055                vf_pp_in_info = &mycs->capture_pp_binary.vf_frame_info;
6056        else
6057                vf_pp_in_info = &mycs->primary_binary[mycs->num_primary_stage - 1].vf_frame_info;
6058
6059        /*
6060            * WARNING: The #if def flag has been added below as a
6061            * temporary solution to solve the problem of enabling the
6062            * view finder in a single binary in a capture flow. The
6063            * vf-pp stage has been removed for Skycam in the solution
6064            * provided. The vf-pp stage should be re-introduced when
6065            * required. Thisshould not be considered as a clean solution.
6066            * Proper  * investigation should be done to come up with the clean
6067            * solution.
6068            * */
6069        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
6070                struct ia_css_binary_descr vf_pp_descr;
6071
6072                ia_css_pipe_get_vfpp_binarydesc(pipe,
6073                                                &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
6074                err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary);
6075                if (err) {
6076                        IA_CSS_LEAVE_ERR_PRIVATE(err);
6077                        return err;
6078                }
6079        }
6080        err = allocate_delay_frames(pipe);
6081
6082        if (err)
6083                return err;
6084
6085#ifdef ISP2401
6086        /* When the input system is 2401, only the Direct Sensor Mode
6087            * Offline Capture uses the ISP copy binary.
6088            */
6089        need_isp_copy_binary = !online && sensor;
6090#else
6091        need_isp_copy_binary = !online && !continuous && !memory;
6092#endif
6093
6094        /* ISP Copy */
6095        if (need_isp_copy_binary) {
6096                err = load_copy_binary(pipe,
6097                                       &mycs->copy_binary,
6098                                       &mycs->primary_binary[0]);
6099                if (err) {
6100                        IA_CSS_LEAVE_ERR_PRIVATE(err);
6101                        return err;
6102                }
6103        }
6104
6105        return 0;
6106}
6107
6108static int
6109allocate_delay_frames(struct ia_css_pipe *pipe)
6110{
6111        unsigned int num_delay_frames = 0, i = 0;
6112        unsigned int dvs_frame_delay = 0;
6113        struct ia_css_frame_info ref_info;
6114        int err = 0;
6115        enum ia_css_pipe_id mode = IA_CSS_PIPE_ID_VIDEO;
6116        struct ia_css_frame **delay_frames = NULL;
6117
6118        IA_CSS_ENTER_PRIVATE("");
6119
6120        if (!pipe) {
6121                IA_CSS_ERROR("Invalid args - pipe %p", pipe);
6122                return -EINVAL;
6123        }
6124
6125        mode = pipe->mode;
6126        dvs_frame_delay = pipe->dvs_frame_delay;
6127
6128        if (dvs_frame_delay > 0)
6129                num_delay_frames = dvs_frame_delay + 1;
6130
6131        switch (mode) {
6132        case IA_CSS_PIPE_ID_CAPTURE: {
6133                struct ia_css_capture_settings *mycs_capture = &pipe->pipe_settings.capture;
6134                (void)mycs_capture;
6135                return err;
6136        }
6137        break;
6138        case IA_CSS_PIPE_ID_VIDEO: {
6139                struct ia_css_video_settings *mycs_video = &pipe->pipe_settings.video;
6140
6141                ref_info = mycs_video->video_binary.internal_frame_info;
6142                /*The ref frame expects
6143                    *   1. Y plane
6144                    *   2. UV plane with line interleaving, like below
6145                    *           UUUUUU(width/2 times) VVVVVVVV..(width/2 times)
6146                    *
6147                    *   This format is not YUV420(which has Y, U and V planes).
6148                    *   Its closer to NV12, except that the UV plane has UV
6149                    *   interleaving, like UVUVUVUVUVUVUVUVU...
6150                    *
6151                    *   TODO: make this ref_frame format as a separate frame format
6152                    */
6153                ref_info.format        = IA_CSS_FRAME_FORMAT_NV12;
6154                delay_frames = mycs_video->delay_frames;
6155        }
6156        break;
6157        case IA_CSS_PIPE_ID_PREVIEW: {
6158                struct ia_css_preview_settings *mycs_preview = &pipe->pipe_settings.preview;
6159
6160                ref_info = mycs_preview->preview_binary.internal_frame_info;
6161                /*The ref frame expects
6162                    *   1. Y plane
6163                    *   2. UV plane with line interleaving, like below
6164                    *           UUUUUU(width/2 times) VVVVVVVV..(width/2 times)
6165                    *
6166                    *   This format is not YUV420(which has Y, U and V planes).
6167                    *   Its closer to NV12, except that the UV plane has UV
6168                    *   interleaving, like UVUVUVUVUVUVUVUVU...
6169                    *
6170                    *   TODO: make this ref_frame format as a separate frame format
6171                    */
6172                ref_info.format        = IA_CSS_FRAME_FORMAT_NV12;
6173                delay_frames = mycs_preview->delay_frames;
6174        }
6175        break;
6176        default:
6177                return -EINVAL;
6178        }
6179
6180        ref_info.raw_bit_depth = SH_CSS_REF_BIT_DEPTH;
6181
6182        assert(num_delay_frames <= MAX_NUM_VIDEO_DELAY_FRAMES);
6183        for (i = 0; i < num_delay_frames; i++) {
6184                err = ia_css_frame_allocate_from_info(&delay_frames[i], &ref_info);
6185                if (err)
6186                        return err;
6187        }
6188        IA_CSS_LEAVE_PRIVATE("");
6189        return 0;
6190}
6191
6192static int load_advanced_binaries(struct ia_css_pipe *pipe)
6193{
6194        struct ia_css_frame_info pre_in_info, gdc_in_info,
6195                        post_in_info, post_out_info,
6196                        vf_info, *vf_pp_in_info, *pipe_out_info,
6197                        *pipe_vf_out_info;
6198        bool need_pp;
6199        bool need_isp_copy = true;
6200        int err = 0;
6201
6202        IA_CSS_ENTER_PRIVATE("");
6203
6204        assert(pipe);
6205        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6206               pipe->mode == IA_CSS_PIPE_ID_COPY);
6207        if (pipe->pipe_settings.capture.pre_isp_binary.info)
6208                return 0;
6209        pipe_out_info = &pipe->output_info[0];
6210        pipe_vf_out_info = &pipe->vf_output_info[0];
6211
6212        vf_info = *pipe_vf_out_info;
6213        err = ia_css_util_check_vf_out_info(pipe_out_info, &vf_info);
6214        if (err)
6215                return err;
6216        need_pp = need_capture_pp(pipe);
6217
6218        ia_css_frame_info_set_format(&vf_info,
6219                                     IA_CSS_FRAME_FORMAT_YUV_LINE);
6220
6221        /* we build up the pipeline starting at the end */
6222        /* Capture post-processing */
6223        if (need_pp) {
6224                struct ia_css_binary_descr capture_pp_descr;
6225
6226                ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
6227                                                     &post_out_info,
6228                                                     pipe_out_info, &vf_info);
6229                err = ia_css_binary_find(&capture_pp_descr,
6230                                         &pipe->pipe_settings.capture.capture_pp_binary);
6231                if (err)
6232                        return err;
6233        } else {
6234                post_out_info = *pipe_out_info;
6235        }
6236
6237        /* Post-gdc */
6238        {
6239                struct ia_css_binary_descr post_gdc_descr;
6240
6241                ia_css_pipe_get_post_gdc_binarydesc(pipe, &post_gdc_descr,
6242                                                    &post_in_info,
6243                                                    &post_out_info, &vf_info);
6244                err = ia_css_binary_find(&post_gdc_descr,
6245                                         &pipe->pipe_settings.capture.post_isp_binary);
6246                if (err)
6247                        return err;
6248        }
6249
6250        /* Gdc */
6251        {
6252                struct ia_css_binary_descr gdc_descr;
6253
6254                ia_css_pipe_get_gdc_binarydesc(pipe, &gdc_descr, &gdc_in_info,
6255                                               &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
6256                err = ia_css_binary_find(&gdc_descr,
6257                                         &pipe->pipe_settings.capture.anr_gdc_binary);
6258                if (err)
6259                        return err;
6260        }
6261        pipe->pipe_settings.capture.anr_gdc_binary.left_padding =
6262            pipe->pipe_settings.capture.post_isp_binary.left_padding;
6263
6264        /* Pre-gdc */
6265        {
6266                struct ia_css_binary_descr pre_gdc_descr;
6267
6268                ia_css_pipe_get_pre_gdc_binarydesc(pipe, &pre_gdc_descr, &pre_in_info,
6269                                                   &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
6270                err = ia_css_binary_find(&pre_gdc_descr,
6271                                         &pipe->pipe_settings.capture.pre_isp_binary);
6272                if (err)
6273                        return err;
6274        }
6275        pipe->pipe_settings.capture.pre_isp_binary.left_padding =
6276            pipe->pipe_settings.capture.anr_gdc_binary.left_padding;
6277
6278        /* Viewfinder post-processing */
6279        if (need_pp) {
6280                vf_pp_in_info =
6281                    &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info;
6282        } else {
6283                vf_pp_in_info =
6284                    &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info;
6285        }
6286
6287        {
6288                struct ia_css_binary_descr vf_pp_descr;
6289
6290                ia_css_pipe_get_vfpp_binarydesc(pipe,
6291                                                &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
6292                err = ia_css_binary_find(&vf_pp_descr,
6293                                         &pipe->pipe_settings.capture.vf_pp_binary);
6294                if (err)
6295                        return err;
6296        }
6297
6298        /* Copy */
6299#ifdef ISP2401
6300        /* For CSI2+, only the direct sensor mode/online requires ISP copy */
6301        need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
6302#endif
6303        if (need_isp_copy)
6304                load_copy_binary(pipe,
6305                                 &pipe->pipe_settings.capture.copy_binary,
6306                                 &pipe->pipe_settings.capture.pre_isp_binary);
6307
6308        return err;
6309}
6310
6311static int load_bayer_isp_binaries(struct ia_css_pipe *pipe)
6312{
6313        struct ia_css_frame_info pre_isp_in_info, *pipe_out_info;
6314        int err = 0;
6315        struct ia_css_binary_descr pre_de_descr;
6316
6317        IA_CSS_ENTER_PRIVATE("");
6318        assert(pipe);
6319        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6320               pipe->mode == IA_CSS_PIPE_ID_COPY);
6321        pipe_out_info = &pipe->output_info[0];
6322
6323        if (pipe->pipe_settings.capture.pre_isp_binary.info)
6324                return 0;
6325
6326        err = ia_css_frame_check_info(pipe_out_info);
6327        if (err)
6328                return err;
6329
6330        ia_css_pipe_get_pre_de_binarydesc(pipe, &pre_de_descr,
6331                                          &pre_isp_in_info,
6332                                          pipe_out_info);
6333
6334        err = ia_css_binary_find(&pre_de_descr,
6335                                 &pipe->pipe_settings.capture.pre_isp_binary);
6336
6337        return err;
6338}
6339
6340static int load_low_light_binaries(struct ia_css_pipe *pipe)
6341{
6342        struct ia_css_frame_info pre_in_info, anr_in_info,
6343                        post_in_info, post_out_info,
6344                        vf_info, *pipe_vf_out_info, *pipe_out_info,
6345                        *vf_pp_in_info;
6346        bool need_pp;
6347        bool need_isp_copy = true;
6348        int err = 0;
6349
6350        IA_CSS_ENTER_PRIVATE("");
6351        assert(pipe);
6352        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6353               pipe->mode == IA_CSS_PIPE_ID_COPY);
6354
6355        if (pipe->pipe_settings.capture.pre_isp_binary.info)
6356                return 0;
6357        pipe_vf_out_info = &pipe->vf_output_info[0];
6358        pipe_out_info = &pipe->output_info[0];
6359
6360        vf_info = *pipe_vf_out_info;
6361        err = ia_css_util_check_vf_out_info(pipe_out_info,
6362                                            &vf_info);
6363        if (err)
6364                return err;
6365        need_pp = need_capture_pp(pipe);
6366
6367        ia_css_frame_info_set_format(&vf_info,
6368                                     IA_CSS_FRAME_FORMAT_YUV_LINE);
6369
6370        /* we build up the pipeline starting at the end */
6371        /* Capture post-processing */
6372        if (need_pp) {
6373                struct ia_css_binary_descr capture_pp_descr;
6374
6375                ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
6376                                                     &post_out_info,
6377                                                     pipe_out_info, &vf_info);
6378                err = ia_css_binary_find(&capture_pp_descr,
6379                                         &pipe->pipe_settings.capture.capture_pp_binary);
6380                if (err)
6381                        return err;
6382        } else {
6383                post_out_info = *pipe_out_info;
6384        }
6385
6386        /* Post-anr */
6387        {
6388                struct ia_css_binary_descr post_anr_descr;
6389
6390                ia_css_pipe_get_post_anr_binarydesc(pipe,
6391                                                    &post_anr_descr, &post_in_info, &post_out_info, &vf_info);
6392                err = ia_css_binary_find(&post_anr_descr,
6393                                         &pipe->pipe_settings.capture.post_isp_binary);
6394                if (err)
6395                        return err;
6396        }
6397
6398        /* Anr */
6399        {
6400                struct ia_css_binary_descr anr_descr;
6401
6402                ia_css_pipe_get_anr_binarydesc(pipe, &anr_descr, &anr_in_info,
6403                                               &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
6404                err = ia_css_binary_find(&anr_descr,
6405                                         &pipe->pipe_settings.capture.anr_gdc_binary);
6406                if (err)
6407                        return err;
6408        }
6409        pipe->pipe_settings.capture.anr_gdc_binary.left_padding =
6410            pipe->pipe_settings.capture.post_isp_binary.left_padding;
6411
6412        /* Pre-anr */
6413        {
6414                struct ia_css_binary_descr pre_anr_descr;
6415
6416                ia_css_pipe_get_pre_anr_binarydesc(pipe, &pre_anr_descr, &pre_in_info,
6417                                                   &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
6418                err = ia_css_binary_find(&pre_anr_descr,
6419                                         &pipe->pipe_settings.capture.pre_isp_binary);
6420                if (err)
6421                        return err;
6422        }
6423        pipe->pipe_settings.capture.pre_isp_binary.left_padding =
6424            pipe->pipe_settings.capture.anr_gdc_binary.left_padding;
6425
6426        /* Viewfinder post-processing */
6427        if (need_pp) {
6428                vf_pp_in_info =
6429                    &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info;
6430        } else {
6431                vf_pp_in_info =
6432                    &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info;
6433        }
6434
6435        {
6436                struct ia_css_binary_descr vf_pp_descr;
6437
6438                ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
6439                                                vf_pp_in_info, pipe_vf_out_info);
6440                err = ia_css_binary_find(&vf_pp_descr,
6441                                         &pipe->pipe_settings.capture.vf_pp_binary);
6442                if (err)
6443                        return err;
6444        }
6445
6446        /* Copy */
6447#ifdef ISP2401
6448        /* For CSI2+, only the direct sensor mode/online requires ISP copy */
6449        need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
6450#endif
6451        if (need_isp_copy)
6452                err = load_copy_binary(pipe,
6453                                       &pipe->pipe_settings.capture.copy_binary,
6454                                       &pipe->pipe_settings.capture.pre_isp_binary);
6455
6456        return err;
6457}
6458
6459static bool copy_on_sp(struct ia_css_pipe *pipe)
6460{
6461        bool rval;
6462
6463        assert(pipe);
6464        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "copy_on_sp() enter:\n");
6465
6466        rval = true;
6467
6468        rval &= (pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
6469
6470        rval &= (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW);
6471
6472        rval &= ((pipe->stream->config.input_config.format ==
6473                    ATOMISP_INPUT_FORMAT_BINARY_8) ||
6474                    (pipe->config.mode == IA_CSS_PIPE_MODE_COPY));
6475
6476        return rval;
6477}
6478
6479static int load_capture_binaries(struct ia_css_pipe *pipe)
6480{
6481        int err = 0;
6482        bool must_be_raw;
6483
6484        IA_CSS_ENTER_PRIVATE("");
6485        assert(pipe);
6486        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6487               pipe->mode == IA_CSS_PIPE_ID_COPY);
6488
6489        if (pipe->pipe_settings.capture.primary_binary[0].info) {
6490                IA_CSS_LEAVE_ERR_PRIVATE(0);
6491                return 0;
6492        }
6493
6494        /* in primary, advanced,low light or bayer,
6495                                                the input format must be raw */
6496        must_be_raw =
6497            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_ADVANCED ||
6498            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER ||
6499            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT;
6500        err = ia_css_util_check_input(&pipe->stream->config, must_be_raw, false);
6501        if (err) {
6502                IA_CSS_LEAVE_ERR_PRIVATE(err);
6503                return err;
6504        }
6505        if (copy_on_sp(pipe) &&
6506            pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
6507                ia_css_frame_info_init(
6508                    &pipe->output_info[0],
6509                    JPEG_BYTES,
6510                    1,
6511                    IA_CSS_FRAME_FORMAT_BINARY_8,
6512                    0);
6513                IA_CSS_LEAVE_ERR_PRIVATE(0);
6514                return 0;
6515        }
6516
6517        switch (pipe->config.default_capture_config.mode) {
6518        case IA_CSS_CAPTURE_MODE_RAW:
6519                err = load_copy_binaries(pipe);
6520#if defined(ISP2401)
6521                if (!err)
6522                        pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online;
6523#endif
6524                break;
6525        case IA_CSS_CAPTURE_MODE_BAYER:
6526                err = load_bayer_isp_binaries(pipe);
6527                break;
6528        case IA_CSS_CAPTURE_MODE_PRIMARY:
6529                err = load_primary_binaries(pipe);
6530                break;
6531        case IA_CSS_CAPTURE_MODE_ADVANCED:
6532                err = load_advanced_binaries(pipe);
6533                break;
6534        case IA_CSS_CAPTURE_MODE_LOW_LIGHT:
6535                err = load_low_light_binaries(pipe);
6536                break;
6537        }
6538        if (err) {
6539                IA_CSS_LEAVE_ERR_PRIVATE(err);
6540                return err;
6541        }
6542
6543        IA_CSS_LEAVE_ERR_PRIVATE(err);
6544        return err;
6545}
6546
6547static int
6548unload_capture_binaries(struct ia_css_pipe *pipe)
6549{
6550        unsigned int i;
6551
6552        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
6553
6554        if (!pipe || (pipe->mode != IA_CSS_PIPE_ID_CAPTURE &&
6555                      pipe->mode != IA_CSS_PIPE_ID_COPY)) {
6556                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
6557                return -EINVAL;
6558        }
6559        ia_css_binary_unload(&pipe->pipe_settings.capture.copy_binary);
6560        for (i = 0; i < MAX_NUM_PRIMARY_STAGES; i++)
6561                ia_css_binary_unload(&pipe->pipe_settings.capture.primary_binary[i]);
6562        ia_css_binary_unload(&pipe->pipe_settings.capture.pre_isp_binary);
6563        ia_css_binary_unload(&pipe->pipe_settings.capture.anr_gdc_binary);
6564        ia_css_binary_unload(&pipe->pipe_settings.capture.post_isp_binary);
6565        ia_css_binary_unload(&pipe->pipe_settings.capture.capture_pp_binary);
6566        ia_css_binary_unload(&pipe->pipe_settings.capture.capture_ldc_binary);
6567        ia_css_binary_unload(&pipe->pipe_settings.capture.vf_pp_binary);
6568
6569        for (i = 0; i < pipe->pipe_settings.capture.num_yuv_scaler; i++)
6570                ia_css_binary_unload(&pipe->pipe_settings.capture.yuv_scaler_binary[i]);
6571
6572        kfree(pipe->pipe_settings.capture.is_output_stage);
6573        pipe->pipe_settings.capture.is_output_stage = NULL;
6574        kfree(pipe->pipe_settings.capture.yuv_scaler_binary);
6575        pipe->pipe_settings.capture.yuv_scaler_binary = NULL;
6576
6577        IA_CSS_LEAVE_ERR_PRIVATE(0);
6578        return 0;
6579}
6580
6581static bool
6582need_downscaling(const struct ia_css_resolution in_res,
6583                 const struct ia_css_resolution out_res)
6584{
6585        if (in_res.width > out_res.width || in_res.height > out_res.height)
6586                return true;
6587
6588        return false;
6589}
6590
6591static bool
6592need_yuv_scaler_stage(const struct ia_css_pipe *pipe)
6593{
6594        unsigned int i;
6595        struct ia_css_resolution in_res, out_res;
6596
6597        bool need_format_conversion = false;
6598
6599        IA_CSS_ENTER_PRIVATE("");
6600        assert(pipe);
6601        assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP);
6602
6603        /* TODO: make generic function */
6604        need_format_conversion =
6605            ((pipe->stream->config.input_config.format ==
6606                ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) &&
6607                (pipe->output_info[0].format != IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8));
6608
6609        in_res = pipe->config.input_effective_res;
6610
6611        if (pipe->config.enable_dz)
6612                return true;
6613
6614        if ((pipe->output_info[0].res.width != 0) && need_format_conversion)
6615                return true;
6616
6617        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6618                out_res = pipe->output_info[i].res;
6619
6620                /* A non-zero width means it is a valid output port */
6621                if ((out_res.width != 0) && need_downscaling(in_res, out_res))
6622                        return true;
6623        }
6624
6625        return false;
6626}
6627
6628/* TODO: it is temporarily created from ia_css_pipe_create_cas_scaler_desc */
6629/* which has some hard-coded knowledge which prevents reuse of the function. */
6630/* Later, merge this with ia_css_pipe_create_cas_scaler_desc */
6631static int ia_css_pipe_create_cas_scaler_desc_single_output(
6632            struct ia_css_frame_info *cas_scaler_in_info,
6633            struct ia_css_frame_info *cas_scaler_out_info,
6634            struct ia_css_frame_info *cas_scaler_vf_info,
6635            struct ia_css_cas_binary_descr *descr)
6636{
6637        unsigned int i;
6638        unsigned int hor_ds_factor = 0, ver_ds_factor = 0;
6639        int err = 0;
6640        struct ia_css_frame_info tmp_in_info;
6641
6642        unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP;
6643
6644        assert(cas_scaler_in_info);
6645        assert(cas_scaler_out_info);
6646
6647        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6648                            "ia_css_pipe_create_cas_scaler_desc() enter:\n");
6649
6650        /* We assume that this function is used only for single output port case. */
6651        descr->num_output_stage = 1;
6652
6653        hor_ds_factor = CEIL_DIV(cas_scaler_in_info->res.width,
6654                                 cas_scaler_out_info->res.width);
6655        ver_ds_factor = CEIL_DIV(cas_scaler_in_info->res.height,
6656                                 cas_scaler_out_info->res.height);
6657        /* use the same horizontal and vertical downscaling factor for simplicity */
6658        assert(hor_ds_factor == ver_ds_factor);
6659
6660        i = 1;
6661        while (i < hor_ds_factor) {
6662                descr->num_stage++;
6663                i *= max_scale_factor_per_stage;
6664        }
6665
6666        descr->in_info = kmalloc(descr->num_stage *
6667                                 sizeof(struct ia_css_frame_info),
6668                                 GFP_KERNEL);
6669        if (!descr->in_info) {
6670                err = -ENOMEM;
6671                goto ERR;
6672        }
6673        descr->internal_out_info = kmalloc(descr->num_stage *
6674                                           sizeof(struct ia_css_frame_info),
6675                                           GFP_KERNEL);
6676        if (!descr->internal_out_info) {
6677                err = -ENOMEM;
6678                goto ERR;
6679        }
6680        descr->out_info = kmalloc(descr->num_stage *
6681                                  sizeof(struct ia_css_frame_info),
6682                                  GFP_KERNEL);
6683        if (!descr->out_info) {
6684                err = -ENOMEM;
6685                goto ERR;
6686        }
6687        descr->vf_info = kmalloc(descr->num_stage *
6688                                 sizeof(struct ia_css_frame_info),
6689                                 GFP_KERNEL);
6690        if (!descr->vf_info) {
6691                err = -ENOMEM;
6692                goto ERR;
6693        }
6694        descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
6695                                         GFP_KERNEL);
6696        if (!descr->is_output_stage) {
6697                err = -ENOMEM;
6698                goto ERR;
6699        }
6700
6701        tmp_in_info = *cas_scaler_in_info;
6702        for (i = 0; i < descr->num_stage; i++) {
6703                descr->in_info[i] = tmp_in_info;
6704                if ((tmp_in_info.res.width / max_scale_factor_per_stage) <=
6705                    cas_scaler_out_info->res.width) {
6706                        descr->is_output_stage[i] = true;
6707                        if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) {
6708                                descr->internal_out_info[i].res.width = cas_scaler_out_info->res.width;
6709                                descr->internal_out_info[i].res.height = cas_scaler_out_info->res.height;
6710                                descr->internal_out_info[i].padded_width = cas_scaler_out_info->padded_width;
6711                                descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6712                        } else {
6713                                assert(i == (descr->num_stage - 1));
6714                                descr->internal_out_info[i].res.width = 0;
6715                                descr->internal_out_info[i].res.height = 0;
6716                        }
6717                        descr->out_info[i].res.width = cas_scaler_out_info->res.width;
6718                        descr->out_info[i].res.height = cas_scaler_out_info->res.height;
6719                        descr->out_info[i].padded_width = cas_scaler_out_info->padded_width;
6720                        descr->out_info[i].format = cas_scaler_out_info->format;
6721                        if (cas_scaler_vf_info) {
6722                                descr->vf_info[i].res.width = cas_scaler_vf_info->res.width;
6723                                descr->vf_info[i].res.height = cas_scaler_vf_info->res.height;
6724                                descr->vf_info[i].padded_width = cas_scaler_vf_info->padded_width;
6725                                ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE);
6726                        } else {
6727                                descr->vf_info[i].res.width = 0;
6728                                descr->vf_info[i].res.height = 0;
6729                                descr->vf_info[i].padded_width = 0;
6730                        }
6731                } else {
6732                        descr->is_output_stage[i] = false;
6733                        descr->internal_out_info[i].res.width = tmp_in_info.res.width /
6734                                                                max_scale_factor_per_stage;
6735                        descr->internal_out_info[i].res.height = tmp_in_info.res.height /
6736                                max_scale_factor_per_stage;
6737                        descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6738                        ia_css_frame_info_init(&descr->internal_out_info[i],
6739                                               tmp_in_info.res.width / max_scale_factor_per_stage,
6740                                               tmp_in_info.res.height / max_scale_factor_per_stage,
6741                                               IA_CSS_FRAME_FORMAT_YUV420, 0);
6742                        descr->out_info[i].res.width = 0;
6743                        descr->out_info[i].res.height = 0;
6744                        descr->vf_info[i].res.width = 0;
6745                        descr->vf_info[i].res.height = 0;
6746                }
6747                tmp_in_info = descr->internal_out_info[i];
6748        }
6749ERR:
6750        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6751                            "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n",
6752                            err);
6753        return err;
6754}
6755
6756/* FIXME: merge most of this and single output version */
6757static int
6758ia_css_pipe_create_cas_scaler_desc(struct ia_css_pipe *pipe,
6759                                   struct ia_css_cas_binary_descr *descr)
6760{
6761        struct ia_css_frame_info in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
6762        struct ia_css_frame_info *out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6763        struct ia_css_frame_info *vf_out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6764        struct ia_css_frame_info tmp_in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
6765        unsigned int i, j;
6766        unsigned int hor_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE],
6767                    ver_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE],
6768                    scale_factor = 0;
6769        unsigned int num_stages = 0;
6770        int err = 0;
6771
6772        unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP;
6773
6774        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6775                            "ia_css_pipe_create_cas_scaler_desc() enter:\n");
6776
6777        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6778                out_info[i] = NULL;
6779                vf_out_info[i] = NULL;
6780                hor_scale_factor[i] = 0;
6781                ver_scale_factor[i] = 0;
6782        }
6783
6784        in_info.res = pipe->config.input_effective_res;
6785        in_info.padded_width = in_info.res.width;
6786        descr->num_output_stage = 0;
6787        /* Find out how much scaling we need for each output */
6788        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6789                if (pipe->output_info[i].res.width != 0) {
6790                        out_info[i] = &pipe->output_info[i];
6791                        if (pipe->vf_output_info[i].res.width != 0)
6792                                vf_out_info[i] = &pipe->vf_output_info[i];
6793                        descr->num_output_stage += 1;
6794                }
6795
6796                if (out_info[i]) {
6797                        hor_scale_factor[i] = CEIL_DIV(in_info.res.width, out_info[i]->res.width);
6798                        ver_scale_factor[i] = CEIL_DIV(in_info.res.height, out_info[i]->res.height);
6799                        /* use the same horizontal and vertical scaling factor for simplicity */
6800                        assert(hor_scale_factor[i] == ver_scale_factor[i]);
6801                        scale_factor = 1;
6802                        do {
6803                                num_stages++;
6804                                scale_factor *= max_scale_factor_per_stage;
6805                        } while (scale_factor < hor_scale_factor[i]);
6806
6807                        in_info.res = out_info[i]->res;
6808                }
6809        }
6810
6811        if (need_yuv_scaler_stage(pipe) && (num_stages == 0))
6812                num_stages = 1;
6813
6814        descr->num_stage = num_stages;
6815
6816        descr->in_info = kmalloc_array(descr->num_stage,
6817                                       sizeof(struct ia_css_frame_info),
6818                                       GFP_KERNEL);
6819        if (!descr->in_info) {
6820                err = -ENOMEM;
6821                goto ERR;
6822        }
6823        descr->internal_out_info = kmalloc(descr->num_stage *
6824                                           sizeof(struct ia_css_frame_info),
6825                                           GFP_KERNEL);
6826        if (!descr->internal_out_info) {
6827                err = -ENOMEM;
6828                goto ERR;
6829        }
6830        descr->out_info = kmalloc(descr->num_stage *
6831                                  sizeof(struct ia_css_frame_info),
6832                                  GFP_KERNEL);
6833        if (!descr->out_info) {
6834                err = -ENOMEM;
6835                goto ERR;
6836        }
6837        descr->vf_info = kmalloc(descr->num_stage *
6838                                 sizeof(struct ia_css_frame_info),
6839                                 GFP_KERNEL);
6840        if (!descr->vf_info) {
6841                err = -ENOMEM;
6842                goto ERR;
6843        }
6844        descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
6845                                         GFP_KERNEL);
6846        if (!descr->is_output_stage) {
6847                err = -ENOMEM;
6848                goto ERR;
6849        }
6850
6851        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6852                if (out_info[i]) {
6853                        if (i > 0) {
6854                                assert((out_info[i - 1]->res.width >= out_info[i]->res.width) &&
6855                                       (out_info[i - 1]->res.height >= out_info[i]->res.height));
6856                        }
6857                }
6858        }
6859
6860        tmp_in_info.res = pipe->config.input_effective_res;
6861        tmp_in_info.format = IA_CSS_FRAME_FORMAT_YUV420;
6862        for (i = 0, j = 0; i < descr->num_stage; i++) {
6863                assert(j < 2);
6864                assert(out_info[j]);
6865
6866                descr->in_info[i] = tmp_in_info;
6867                if ((tmp_in_info.res.width / max_scale_factor_per_stage) <=
6868                    out_info[j]->res.width) {
6869                        descr->is_output_stage[i] = true;
6870                        if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) {
6871                                descr->internal_out_info[i].res.width = out_info[j]->res.width;
6872                                descr->internal_out_info[i].res.height = out_info[j]->res.height;
6873                                descr->internal_out_info[i].padded_width = out_info[j]->padded_width;
6874                                descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6875                        } else {
6876                                assert(i == (descr->num_stage - 1));
6877                                descr->internal_out_info[i].res.width = 0;
6878                                descr->internal_out_info[i].res.height = 0;
6879                        }
6880                        descr->out_info[i].res.width = out_info[j]->res.width;
6881                        descr->out_info[i].res.height = out_info[j]->res.height;
6882                        descr->out_info[i].padded_width = out_info[j]->padded_width;
6883                        descr->out_info[i].format = out_info[j]->format;
6884                        if (vf_out_info[j]) {
6885                                descr->vf_info[i].res.width = vf_out_info[j]->res.width;
6886                                descr->vf_info[i].res.height = vf_out_info[j]->res.height;
6887                                descr->vf_info[i].padded_width = vf_out_info[j]->padded_width;
6888                                ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE);
6889                        } else {
6890                                descr->vf_info[i].res.width = 0;
6891                                descr->vf_info[i].res.height = 0;
6892                                descr->vf_info[i].padded_width = 0;
6893                        }
6894                        j++;
6895                } else {
6896                        descr->is_output_stage[i] = false;
6897                        descr->internal_out_info[i].res.width = tmp_in_info.res.width /
6898                                                                max_scale_factor_per_stage;
6899                        descr->internal_out_info[i].res.height = tmp_in_info.res.height /
6900                                max_scale_factor_per_stage;
6901                        descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6902                        ia_css_frame_info_init(&descr->internal_out_info[i],
6903                                               tmp_in_info.res.width / max_scale_factor_per_stage,
6904                                               tmp_in_info.res.height / max_scale_factor_per_stage,
6905                                               IA_CSS_FRAME_FORMAT_YUV420, 0);
6906                        descr->out_info[i].res.width = 0;
6907                        descr->out_info[i].res.height = 0;
6908                        descr->vf_info[i].res.width = 0;
6909                        descr->vf_info[i].res.height = 0;
6910                }
6911                tmp_in_info = descr->internal_out_info[i];
6912        }
6913ERR:
6914        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6915                            "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n",
6916                            err);
6917        return err;
6918}
6919
6920static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
6921        *descr)
6922{
6923        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6924                            "ia_css_pipe_destroy_cas_scaler_desc() enter:\n");
6925        kfree(descr->in_info);
6926        descr->in_info = NULL;
6927        kfree(descr->internal_out_info);
6928        descr->internal_out_info = NULL;
6929        kfree(descr->out_info);
6930        descr->out_info = NULL;
6931        kfree(descr->vf_info);
6932        descr->vf_info = NULL;
6933        kfree(descr->is_output_stage);
6934        descr->is_output_stage = NULL;
6935        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6936                            "ia_css_pipe_destroy_cas_scaler_desc() leave\n");
6937}
6938
6939static int
6940load_yuvpp_binaries(struct ia_css_pipe *pipe)
6941{
6942        int err = 0;
6943        bool need_scaler = false;
6944        struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6945        struct ia_css_yuvpp_settings *mycs;
6946        struct ia_css_binary *next_binary;
6947        struct ia_css_cas_binary_descr cas_scaler_descr = { };
6948        unsigned int i, j;
6949        bool need_isp_copy_binary = false;
6950
6951        IA_CSS_ENTER_PRIVATE("");
6952        assert(pipe);
6953        assert(pipe->stream);
6954        assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP);
6955
6956        if (pipe->pipe_settings.yuvpp.copy_binary.info)
6957                goto ERR;
6958
6959        /* Set both must_be_raw and must_be_yuv to false then yuvpp can take rgb inputs */
6960        err = ia_css_util_check_input(&pipe->stream->config, false, false);
6961        if (err)
6962                goto ERR;
6963
6964        mycs = &pipe->pipe_settings.yuvpp;
6965
6966        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6967                if (pipe->vf_output_info[i].res.width != 0) {
6968                        err = ia_css_util_check_vf_out_info(&pipe->output_info[i],
6969                                                            &pipe->vf_output_info[i]);
6970                        if (err)
6971                                goto ERR;
6972                }
6973                vf_pp_in_info[i] = NULL;
6974        }
6975
6976        need_scaler = need_yuv_scaler_stage(pipe);
6977
6978        /* we build up the pipeline starting at the end */
6979        /* Capture post-processing */
6980        if (need_scaler) {
6981                struct ia_css_binary_descr yuv_scaler_descr;
6982
6983                err = ia_css_pipe_create_cas_scaler_desc(pipe,
6984                                                         &cas_scaler_descr);
6985                if (err)
6986                        goto ERR;
6987                mycs->num_output = cas_scaler_descr.num_output_stage;
6988                mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
6989                mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage,
6990                                                  sizeof(struct ia_css_binary),
6991                                                  GFP_KERNEL);
6992                if (!mycs->yuv_scaler_binary) {
6993                        err = -ENOMEM;
6994                        goto ERR;
6995                }
6996                mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage,
6997                                                sizeof(bool), GFP_KERNEL);
6998                if (!mycs->is_output_stage) {
6999                        err = -ENOMEM;
7000                        goto ERR;
7001                }
7002                for (i = 0; i < cas_scaler_descr.num_stage; i++) {
7003                        mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
7004                        ia_css_pipe_get_yuvscaler_binarydesc(pipe,
7005                                                             &yuv_scaler_descr,
7006                                                             &cas_scaler_descr.in_info[i],
7007                                                             &cas_scaler_descr.out_info[i],
7008                                                             &cas_scaler_descr.internal_out_info[i],
7009                                                             &cas_scaler_descr.vf_info[i]);
7010                        err = ia_css_binary_find(&yuv_scaler_descr,
7011                                                 &mycs->yuv_scaler_binary[i]);
7012                        if (err)
7013                                goto ERR;
7014                }
7015                ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
7016        } else {
7017                mycs->num_output = 1;
7018        }
7019
7020        if (need_scaler)
7021                next_binary = &mycs->yuv_scaler_binary[0];
7022        else
7023                next_binary = NULL;
7024
7025#if defined(ISP2401)
7026        /*
7027            * NOTES
7028            * - Why does the "yuvpp" pipe needs "isp_copy_binary" (i.e. ISP Copy) when
7029            *   its input is "ATOMISP_INPUT_FORMAT_YUV422_8"?
7030            *
7031            *   In most use cases, the first stage in the "yuvpp" pipe is the "yuv_scale_
7032            *   binary". However, the "yuv_scale_binary" does NOT support the input-frame
7033            *   format as "IA_CSS_STREAM _FORMAT_YUV422_8".
7034            *
7035            *   Hence, the "isp_copy_binary" is required to be present in front of the "yuv
7036            *   _scale_binary". It would translate the input-frame to the frame formats that
7037            *   are supported by the "yuv_scale_binary".
7038            *
7039            *   Please refer to "FrameWork/css/isp/pipes/capture_pp/capture_pp_1.0/capture_
7040            *   pp_defs.h" for the list of input-frame formats that are supported by the
7041            *   "yuv_scale_binary".
7042            */
7043        need_isp_copy_binary =
7044            (pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_YUV422_8);
7045#else  /* !ISP2401 */
7046        need_isp_copy_binary = true;
7047#endif /*  ISP2401 */
7048
7049        if (need_isp_copy_binary) {
7050                err = load_copy_binary(pipe,
7051                                       &mycs->copy_binary,
7052                                       next_binary);
7053
7054                if (err)
7055                        goto ERR;
7056
7057                /*
7058                    * NOTES
7059                    * - Why is "pipe->pipe_settings.capture.copy_binary.online" specified?
7060                    *
7061                    *   In some use cases, the first stage in the "yuvpp" pipe is the
7062                    *   "isp_copy_binary". The "isp_copy_binary" is designed to process
7063                    *   the input from either the system DDR or from the IPU internal VMEM.
7064                    *   So it provides the flag "online" to specify where its input is from,
7065                    *   i.e.:
7066                    *
7067                    *      (1) "online <= true", the input is from the IPU internal VMEM.
7068                    *      (2) "online <= false", the input is from the system DDR.
7069                    *
7070                    *   In other use cases, the first stage in the "yuvpp" pipe is the
7071                    *   "yuv_scale_binary". "The "yuv_scale_binary" is designed to process the
7072                    *   input ONLY from the system DDR. So it does not provide the flag "online"
7073                    *   to specify where its input is from.
7074                    */
7075                pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online;
7076        }
7077
7078        /* Viewfinder post-processing */
7079        if (need_scaler) {
7080                for (i = 0, j = 0; i < mycs->num_yuv_scaler; i++) {
7081                        if (mycs->is_output_stage[i]) {
7082                                assert(j < 2);
7083                                vf_pp_in_info[j] =
7084                                    &mycs->yuv_scaler_binary[i].vf_frame_info;
7085                                j++;
7086                        }
7087                }
7088                mycs->num_vf_pp = j;
7089        } else {
7090                vf_pp_in_info[0] =
7091                    &mycs->copy_binary.vf_frame_info;
7092                for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
7093                        vf_pp_in_info[i] = NULL;
7094
7095                mycs->num_vf_pp = 1;
7096        }
7097        mycs->vf_pp_binary = kcalloc(mycs->num_vf_pp,
7098                                     sizeof(struct ia_css_binary),
7099                                     GFP_KERNEL);
7100        if (!mycs->vf_pp_binary) {
7101                err = -ENOMEM;
7102                goto ERR;
7103        }
7104
7105        {
7106                struct ia_css_binary_descr vf_pp_descr;
7107
7108                for (i = 0; i < mycs->num_vf_pp; i++) {
7109                        if (pipe->vf_output_info[i].res.width != 0) {
7110                                ia_css_pipe_get_vfpp_binarydesc(pipe,
7111                                                                &vf_pp_descr, vf_pp_in_info[i], &pipe->vf_output_info[i]);
7112                                err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary[i]);
7113                                if (err)
7114                                        goto ERR;
7115                        }
7116                }
7117        }
7118
7119        if (err)
7120                goto ERR;
7121
7122ERR:
7123        if (need_scaler)
7124                ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
7125
7126        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "load_yuvpp_binaries() leave, err=%d\n",
7127                            err);
7128        return err;
7129}
7130
7131static int
7132unload_yuvpp_binaries(struct ia_css_pipe *pipe)
7133{
7134        unsigned int i;
7135
7136        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7137
7138        if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
7139                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7140                return -EINVAL;
7141        }
7142        ia_css_binary_unload(&pipe->pipe_settings.yuvpp.copy_binary);
7143        for (i = 0; i < pipe->pipe_settings.yuvpp.num_yuv_scaler; i++)
7144                ia_css_binary_unload(&pipe->pipe_settings.yuvpp.yuv_scaler_binary[i]);
7145
7146        for (i = 0; i < pipe->pipe_settings.yuvpp.num_vf_pp; i++)
7147                ia_css_binary_unload(&pipe->pipe_settings.yuvpp.vf_pp_binary[i]);
7148
7149        kfree(pipe->pipe_settings.yuvpp.is_output_stage);
7150        pipe->pipe_settings.yuvpp.is_output_stage = NULL;
7151        kfree(pipe->pipe_settings.yuvpp.yuv_scaler_binary);
7152        pipe->pipe_settings.yuvpp.yuv_scaler_binary = NULL;
7153        kfree(pipe->pipe_settings.yuvpp.vf_pp_binary);
7154        pipe->pipe_settings.yuvpp.vf_pp_binary = NULL;
7155
7156        IA_CSS_LEAVE_ERR_PRIVATE(0);
7157        return 0;
7158}
7159
7160static int yuvpp_start(struct ia_css_pipe *pipe)
7161{
7162        int err = 0;
7163        enum sh_css_pipe_config_override copy_ovrd;
7164        enum ia_css_input_mode yuvpp_pipe_input_mode;
7165
7166        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7167        if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
7168                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7169                return -EINVAL;
7170        }
7171
7172        yuvpp_pipe_input_mode = pipe->stream->config.mode;
7173
7174        sh_css_metrics_start_frame();
7175
7176        /* multi stream video needs mipi buffers */
7177
7178        err = send_mipi_frames(pipe);
7179        if (err) {
7180                IA_CSS_LEAVE_ERR_PRIVATE(err);
7181                return err;
7182        }
7183
7184        {
7185                unsigned int thread_id;
7186
7187                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
7188                copy_ovrd = 1 << thread_id;
7189        }
7190
7191        start_pipe(pipe, copy_ovrd, yuvpp_pipe_input_mode);
7192
7193        IA_CSS_LEAVE_ERR_PRIVATE(err);
7194        return err;
7195}
7196
7197static int
7198sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe)
7199{
7200        int err = 0;
7201
7202        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7203
7204        if (!pipe) {
7205                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7206                return -EINVAL;
7207        }
7208        /* PIPE_MODE_COPY has no binaries, but has output frames to outside*/
7209        if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
7210                IA_CSS_LEAVE_ERR_PRIVATE(0);
7211                return 0;
7212        }
7213
7214        switch (pipe->mode) {
7215        case IA_CSS_PIPE_ID_PREVIEW:
7216                err = unload_preview_binaries(pipe);
7217                break;
7218        case IA_CSS_PIPE_ID_VIDEO:
7219                err = unload_video_binaries(pipe);
7220                break;
7221        case IA_CSS_PIPE_ID_CAPTURE:
7222                err = unload_capture_binaries(pipe);
7223                break;
7224        case IA_CSS_PIPE_ID_YUVPP:
7225                err = unload_yuvpp_binaries(pipe);
7226                break;
7227        default:
7228                break;
7229        }
7230        IA_CSS_LEAVE_ERR_PRIVATE(err);
7231        return err;
7232}
7233
7234static int
7235sh_css_pipe_load_binaries(struct ia_css_pipe *pipe)
7236{
7237        int err = 0;
7238
7239        assert(pipe);
7240        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "sh_css_pipe_load_binaries() enter:\n");
7241
7242        /* PIPE_MODE_COPY has no binaries, but has output frames to outside*/
7243        if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
7244                return err;
7245
7246        switch (pipe->mode) {
7247        case IA_CSS_PIPE_ID_PREVIEW:
7248                err = load_preview_binaries(pipe);
7249                break;
7250        case IA_CSS_PIPE_ID_VIDEO:
7251                err = load_video_binaries(pipe);
7252                break;
7253        case IA_CSS_PIPE_ID_CAPTURE:
7254                err = load_capture_binaries(pipe);
7255                break;
7256        case IA_CSS_PIPE_ID_YUVPP:
7257                err = load_yuvpp_binaries(pipe);
7258                break;
7259        case IA_CSS_PIPE_ID_ACC:
7260                break;
7261        default:
7262                err = -EINVAL;
7263                break;
7264        }
7265        if (err) {
7266                if (sh_css_pipe_unload_binaries(pipe)) {
7267                        /* currently css does not support multiple error returns in a single function,
7268                            * using -EINVAL in this case */
7269                        err = -EINVAL;
7270                }
7271        }
7272        return err;
7273}
7274
7275static int
7276create_host_yuvpp_pipeline(struct ia_css_pipe *pipe)
7277{
7278        struct ia_css_pipeline *me;
7279        int err = 0;
7280        struct ia_css_pipeline_stage *vf_pp_stage = NULL,
7281                *copy_stage = NULL,
7282                *yuv_scaler_stage = NULL;
7283        struct ia_css_binary *copy_binary,
7284                *vf_pp_binary,
7285                *yuv_scaler_binary;
7286        bool need_scaler = false;
7287        unsigned int num_stage, num_output_stage;
7288        unsigned int i, j;
7289
7290        struct ia_css_frame *in_frame = NULL;
7291        struct ia_css_frame *out_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
7292        struct ia_css_frame *bin_out_frame[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
7293        struct ia_css_frame *vf_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
7294        struct ia_css_pipeline_stage_desc stage_desc;
7295        bool need_in_frameinfo_memory = false;
7296#ifdef ISP2401
7297        bool sensor = false;
7298        bool buffered_sensor = false;
7299        bool online = false;
7300        bool continuous = false;
7301#endif
7302
7303        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7304        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
7305                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7306                return -EINVAL;
7307        }
7308        me = &pipe->pipeline;
7309        ia_css_pipeline_clean(me);
7310        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
7311                out_frame[i] = NULL;
7312                vf_frame[i] = NULL;
7313        }
7314        ia_css_pipe_util_create_output_frames(bin_out_frame);
7315        num_stage  = pipe->pipe_settings.yuvpp.num_yuv_scaler;
7316        num_output_stage   = pipe->pipe_settings.yuvpp.num_output;
7317
7318#ifdef ISP2401
7319        /* When the input system is 2401, always enable 'in_frameinfo_memory'
7320            * except for the following:
7321            * - Direct Sensor Mode Online Capture
7322            * - Direct Sensor Mode Continuous Capture
7323            * - Buffered Sensor Mode Continuous Capture
7324            */
7325        sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
7326        buffered_sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
7327        online = pipe->stream->config.online;
7328        continuous = pipe->stream->config.continuous;
7329        need_in_frameinfo_memory =
7330        !((sensor && (online || continuous)) || (buffered_sensor && continuous));
7331#else
7332        /* Construct in_frame info (only in case we have dynamic input */
7333        need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
7334#endif
7335        /* the input frame can come from:
7336            *  a) memory: connect yuvscaler to me->in_frame
7337            *  b) sensor, via copy binary: connect yuvscaler to copy binary later on */
7338        if (need_in_frameinfo_memory) {
7339                /* TODO: improve for different input formats. */
7340
7341                /*
7342                    * "pipe->stream->config.input_config.format" represents the sensor output
7343                    * frame format, e.g. YUV422 8-bit.
7344                    *
7345                    * "in_frame_format" represents the imaging pipe's input frame format, e.g.
7346                    * Bayer-Quad RAW.
7347                    */
7348                int in_frame_format;
7349
7350                if (pipe->stream->config.input_config.format ==
7351                    ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) {
7352                        in_frame_format = IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8;
7353                } else if (pipe->stream->config.input_config.format ==
7354                            ATOMISP_INPUT_FORMAT_YUV422_8) {
7355                        /*
7356                            * When the sensor output frame format is "ATOMISP_INPUT_FORMAT_YUV422_8",
7357                            * the "isp_copy_var" binary is selected as the first stage in the yuvpp
7358                            * pipe.
7359                            *
7360                            * For the "isp_copy_var" binary, it reads the YUV422-8 pixels from
7361                            * the frame buffer (at DDR) to the frame-line buffer (at VMEM).
7362                            *
7363                            * By now, the "isp_copy_var" binary does NOT provide a separated
7364                            * frame-line buffer to store the YUV422-8 pixels. Instead, it stores
7365                            * the YUV422-8 pixels in the frame-line buffer which is designed to
7366                            * store the Bayer-Quad RAW pixels.
7367                            *
7368                            * To direct the "isp_copy_var" binary reading from the RAW frame-line
7369                            * buffer, its input frame format must be specified as "IA_CSS_FRAME_
7370                            * FORMAT_RAW".
7371                            */
7372                        in_frame_format = IA_CSS_FRAME_FORMAT_RAW;
7373                } else {
7374                        in_frame_format = IA_CSS_FRAME_FORMAT_NV12;
7375                }
7376
7377                err = init_in_frameinfo_memory_defaults(pipe,
7378                                                        &me->in_frame,
7379                                                        in_frame_format);
7380
7381                if (err) {
7382                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7383                        return err;
7384                }
7385
7386                in_frame = &me->in_frame;
7387        } else {
7388                in_frame = NULL;
7389        }
7390
7391        for (i = 0; i < num_output_stage; i++) {
7392                assert(i < IA_CSS_PIPE_MAX_OUTPUT_STAGE);
7393                if (pipe->output_info[i].res.width != 0) {
7394                        err = init_out_frameinfo_defaults(pipe, &me->out_frame[i], i);
7395                        if (err) {
7396                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7397                                return err;
7398                        }
7399                        out_frame[i] = &me->out_frame[i];
7400                }
7401
7402                /* Construct vf_frame info (only in case we have VF) */
7403                if (pipe->vf_output_info[i].res.width != 0) {
7404                        err = init_vf_frameinfo_defaults(pipe, &me->vf_frame[i], i);
7405                        if (err) {
7406                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7407                                return err;
7408                        }
7409                        vf_frame[i] = &me->vf_frame[i];
7410                }
7411        }
7412
7413        copy_binary       = &pipe->pipe_settings.yuvpp.copy_binary;
7414        vf_pp_binary      = pipe->pipe_settings.yuvpp.vf_pp_binary;
7415        yuv_scaler_binary = pipe->pipe_settings.yuvpp.yuv_scaler_binary;
7416        need_scaler = need_yuv_scaler_stage(pipe);
7417
7418        if (pipe->pipe_settings.yuvpp.copy_binary.info) {
7419                struct ia_css_frame *in_frame_local = NULL;
7420
7421#ifdef ISP2401
7422                /* After isp copy is enabled in_frame needs to be passed. */
7423                if (!online)
7424                        in_frame_local = in_frame;
7425#endif
7426
7427                if (need_scaler) {
7428                        ia_css_pipe_util_set_output_frames(bin_out_frame,
7429                                                           0, NULL);
7430                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7431                                                           copy_binary,
7432                                                           bin_out_frame,
7433                                                           in_frame_local,
7434                                                           NULL);
7435                } else {
7436                        ia_css_pipe_util_set_output_frames(bin_out_frame,
7437                                                           0, out_frame[0]);
7438                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7439                                                           copy_binary,
7440                                                           bin_out_frame,
7441                                                           in_frame_local,
7442                                                           NULL);
7443                }
7444
7445                err = ia_css_pipeline_create_and_add_stage(me,
7446                                                           &stage_desc,
7447                                                           &copy_stage);
7448
7449                if (err) {
7450                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7451                        return err;
7452                }
7453
7454                if (copy_stage) {
7455                        /* if we use yuv scaler binary, vf output should be from there */
7456                        copy_stage->args.copy_vf = !need_scaler;
7457                        /* for yuvpp pipe, it should always be enabled */
7458                        copy_stage->args.copy_output = true;
7459                        /* connect output of copy binary to input of yuv scaler */
7460                        in_frame = copy_stage->args.out_frame[0];
7461                }
7462        }
7463
7464        if (need_scaler) {
7465                struct ia_css_frame *tmp_out_frame = NULL;
7466                struct ia_css_frame *tmp_vf_frame = NULL;
7467                struct ia_css_frame *tmp_in_frame = in_frame;
7468
7469                for (i = 0, j = 0; i < num_stage; i++) {
7470                        assert(j < num_output_stage);
7471                        if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
7472                                tmp_out_frame = out_frame[j];
7473                                tmp_vf_frame = vf_frame[j];
7474                        } else {
7475                                tmp_out_frame = NULL;
7476                                tmp_vf_frame = NULL;
7477                        }
7478
7479                        err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
7480                                                   tmp_out_frame,
7481                                                   NULL,
7482                                                   &yuv_scaler_binary[i],
7483                                                   &yuv_scaler_stage);
7484
7485                        if (err) {
7486                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7487                                return err;
7488                        }
7489                        /* we use output port 1 as internal output port */
7490                        tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
7491                        if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
7492                                if (tmp_vf_frame && (tmp_vf_frame->info.res.width != 0)) {
7493                                        in_frame = yuv_scaler_stage->args.out_vf_frame;
7494                                        err = add_vf_pp_stage(pipe, in_frame,
7495                                                              tmp_vf_frame,
7496                                                              &vf_pp_binary[j],
7497                                                              &vf_pp_stage);
7498
7499                                        if (err) {
7500                                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7501                                                return err;
7502                                        }
7503                                }
7504                                j++;
7505                        }
7506                }
7507        } else if (copy_stage) {
7508                if (vf_frame[0] && vf_frame[0]->info.res.width != 0) {
7509                        in_frame = copy_stage->args.out_vf_frame;
7510                        err = add_vf_pp_stage(pipe, in_frame, vf_frame[0],
7511                                              &vf_pp_binary[0], &vf_pp_stage);
7512                }
7513                if (err) {
7514                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7515                        return err;
7516                }
7517        }
7518
7519        ia_css_pipeline_finalize_stages(&pipe->pipeline,
7520                                        pipe->stream->config.continuous);
7521
7522        IA_CSS_LEAVE_ERR_PRIVATE(0);
7523
7524        return 0;
7525}
7526
7527static int
7528create_host_copy_pipeline(struct ia_css_pipe *pipe,
7529                          unsigned int max_input_width,
7530                          struct ia_css_frame *out_frame)
7531{
7532        struct ia_css_pipeline *me;
7533        int err = 0;
7534        struct ia_css_pipeline_stage_desc stage_desc;
7535
7536        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7537                            "create_host_copy_pipeline() enter:\n");
7538
7539        /* pipeline already created as part of create_host_pipeline_structure */
7540        me = &pipe->pipeline;
7541        ia_css_pipeline_clean(me);
7542
7543        /* Construct out_frame info */
7544        out_frame->contiguous = false;
7545        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
7546
7547        if (copy_on_sp(pipe) &&
7548            pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
7549                ia_css_frame_info_init(&out_frame->info, JPEG_BYTES, 1,
7550                                       IA_CSS_FRAME_FORMAT_BINARY_8, 0);
7551        } else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW) {
7552                out_frame->info.raw_bit_depth =
7553                ia_css_pipe_util_pipe_input_format_bpp(pipe);
7554        }
7555
7556        me->num_stages = 1;
7557        me->pipe_id = IA_CSS_PIPE_ID_COPY;
7558        pipe->mode  = IA_CSS_PIPE_ID_COPY;
7559
7560        ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
7561                                           IA_CSS_PIPELINE_RAW_COPY,
7562                                           max_input_width);
7563        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, NULL);
7564
7565        ia_css_pipeline_finalize_stages(&pipe->pipeline,
7566                                        pipe->stream->config.continuous);
7567
7568        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7569                            "create_host_copy_pipeline() leave:\n");
7570
7571        return err;
7572}
7573
7574static int
7575create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe)
7576{
7577        struct ia_css_pipeline *me = &pipe->pipeline;
7578        int err = 0;
7579        struct ia_css_pipeline_stage_desc stage_desc;
7580        struct ia_css_frame *out_frame = &me->out_frame[0];
7581        struct ia_css_pipeline_stage *out_stage = NULL;
7582        unsigned int thread_id;
7583        enum sh_css_queue_id queue_id;
7584        unsigned int max_input_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS;
7585
7586        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7587                            "create_host_isyscopy_capture_pipeline() enter:\n");
7588        ia_css_pipeline_clean(me);
7589
7590        /* Construct out_frame info */
7591        err = sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, 0);
7592        if (err)
7593                return err;
7594        out_frame->contiguous = false;
7595        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
7596        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
7597        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, &queue_id);
7598        out_frame->dynamic_queue_id = queue_id;
7599        out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME;
7600
7601        me->num_stages = 1;
7602        me->pipe_id = IA_CSS_PIPE_ID_CAPTURE;
7603        pipe->mode  = IA_CSS_PIPE_ID_CAPTURE;
7604        ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
7605                                           IA_CSS_PIPELINE_ISYS_COPY,
7606                                           max_input_width);
7607        err = ia_css_pipeline_create_and_add_stage(me,
7608                                                   &stage_desc, &out_stage);
7609        if (err)
7610                return err;
7611
7612        ia_css_pipeline_finalize_stages(me, pipe->stream->config.continuous);
7613
7614        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7615                            "create_host_isyscopy_capture_pipeline() leave:\n");
7616
7617        return err;
7618}
7619
7620static int
7621create_host_regular_capture_pipeline(struct ia_css_pipe *pipe)
7622{
7623        struct ia_css_pipeline *me;
7624        int err = 0;
7625        enum ia_css_capture_mode mode;
7626        struct ia_css_pipeline_stage *current_stage = NULL;
7627        struct ia_css_pipeline_stage *yuv_scaler_stage = NULL;
7628        struct ia_css_binary *copy_binary,
7629                *primary_binary[MAX_NUM_PRIMARY_STAGES],
7630                *vf_pp_binary,
7631                *pre_isp_binary,
7632                *anr_gdc_binary,
7633                *post_isp_binary,
7634                *yuv_scaler_binary,
7635                *capture_pp_binary,
7636                *capture_ldc_binary;
7637        bool need_pp = false;
7638        bool raw;
7639
7640        struct ia_css_frame *in_frame;
7641        struct ia_css_frame *out_frame;
7642        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
7643        struct ia_css_frame *vf_frame;
7644        struct ia_css_pipeline_stage_desc stage_desc;
7645        bool need_in_frameinfo_memory = false;
7646#ifdef ISP2401
7647        bool sensor = false;
7648        bool buffered_sensor = false;
7649        bool online = false;
7650        bool continuous = false;
7651#endif
7652        unsigned int i, num_yuv_scaler, num_primary_stage;
7653        bool need_yuv_pp = false;
7654        bool *is_output_stage = NULL;
7655        bool need_ldc = false;
7656
7657        IA_CSS_ENTER_PRIVATE("");
7658        assert(pipe);
7659        assert(pipe->stream);
7660        assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
7661               pipe->mode == IA_CSS_PIPE_ID_COPY);
7662
7663        me = &pipe->pipeline;
7664        mode = pipe->config.default_capture_config.mode;
7665        raw = (mode == IA_CSS_CAPTURE_MODE_RAW);
7666        ia_css_pipeline_clean(me);
7667        ia_css_pipe_util_create_output_frames(out_frames);
7668
7669#ifdef ISP2401
7670        /* When the input system is 2401, always enable 'in_frameinfo_memory'
7671            * except for the following:
7672            * - Direct Sensor Mode Online Capture
7673            * - Direct Sensor Mode Online Capture
7674            * - Direct Sensor Mode Continuous Capture
7675            * - Buffered Sensor Mode Continuous Capture
7676            */
7677        sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
7678        buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
7679        online = pipe->stream->config.online;
7680        continuous = pipe->stream->config.continuous;
7681        need_in_frameinfo_memory =
7682        !((sensor && (online || continuous)) || (buffered_sensor && (online || continuous)));
7683#else
7684        /* Construct in_frame info (only in case we have dynamic input */
7685        need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
7686#endif
7687        if (need_in_frameinfo_memory) {
7688                err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
7689                                                        IA_CSS_FRAME_FORMAT_RAW);
7690                if (err) {
7691                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7692                        return err;
7693                }
7694
7695                in_frame = &me->in_frame;
7696        } else {
7697                in_frame = NULL;
7698        }
7699
7700        err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
7701        if (err) {
7702                IA_CSS_LEAVE_ERR_PRIVATE(err);
7703                return err;
7704        }
7705        out_frame = &me->out_frame[0];
7706
7707        /* Construct vf_frame info (only in case we have VF) */
7708        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
7709                if (mode == IA_CSS_CAPTURE_MODE_RAW || mode == IA_CSS_CAPTURE_MODE_BAYER) {
7710                        /* These modes don't support viewfinder output */
7711                        vf_frame = NULL;
7712                } else {
7713                        init_vf_frameinfo_defaults(pipe, &me->vf_frame[0], 0);
7714                        vf_frame = &me->vf_frame[0];
7715                }
7716        } else {
7717                vf_frame = NULL;
7718        }
7719
7720        copy_binary       = &pipe->pipe_settings.capture.copy_binary;
7721        num_primary_stage = pipe->pipe_settings.capture.num_primary_stage;
7722        if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY)) {
7723                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7724                return -EINVAL;
7725        }
7726
7727        for (i = 0; i < num_primary_stage; i++)
7728                primary_binary[i] = &pipe->pipe_settings.capture.primary_binary[i];
7729
7730        vf_pp_binary      = &pipe->pipe_settings.capture.vf_pp_binary;
7731        pre_isp_binary    = &pipe->pipe_settings.capture.pre_isp_binary;
7732        anr_gdc_binary    = &pipe->pipe_settings.capture.anr_gdc_binary;
7733        post_isp_binary   = &pipe->pipe_settings.capture.post_isp_binary;
7734        capture_pp_binary = &pipe->pipe_settings.capture.capture_pp_binary;
7735        yuv_scaler_binary = pipe->pipe_settings.capture.yuv_scaler_binary;
7736        num_yuv_scaler    = pipe->pipe_settings.capture.num_yuv_scaler;
7737        is_output_stage   = pipe->pipe_settings.capture.is_output_stage;
7738        capture_ldc_binary = &pipe->pipe_settings.capture.capture_ldc_binary;
7739
7740        need_pp = (need_capture_pp(pipe) || pipe->output_stage) &&
7741                    mode != IA_CSS_CAPTURE_MODE_RAW &&
7742                    mode != IA_CSS_CAPTURE_MODE_BAYER;
7743        need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
7744        need_ldc = (capture_ldc_binary && capture_ldc_binary->info);
7745
7746        if (pipe->pipe_settings.capture.copy_binary.info) {
7747                if (raw) {
7748                        ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7749#if defined(ISP2401)
7750                        if (!continuous) {
7751                                ia_css_pipe_get_generic_stage_desc(&stage_desc,
7752                                                                   copy_binary,
7753                                                                   out_frames,
7754                                                                   in_frame,
7755                                                                   NULL);
7756                        } else {
7757                                in_frame = pipe->stream->last_pipe->continuous_frames[0];
7758                                ia_css_pipe_get_generic_stage_desc(&stage_desc,
7759                                                                   copy_binary,
7760                                                                   out_frames,
7761                                                                   in_frame,
7762                                                                   NULL);
7763                        }
7764#else
7765                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7766                                                           copy_binary,
7767                                                           out_frames,
7768                                                           NULL, NULL);
7769#endif
7770                } else {
7771                        ia_css_pipe_util_set_output_frames(out_frames, 0,
7772                                                           in_frame);
7773                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7774                                                           copy_binary,
7775                                                           out_frames,
7776                                                           NULL, NULL);
7777                }
7778
7779                err = ia_css_pipeline_create_and_add_stage(me,
7780                                                           &stage_desc,
7781                                                           &current_stage);
7782                if (err) {
7783                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7784                        return err;
7785                }
7786        } else if (pipe->stream->config.continuous) {
7787                in_frame = pipe->stream->last_pipe->continuous_frames[0];
7788        }
7789
7790        if (mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
7791                struct ia_css_frame *local_in_frame = NULL;
7792                struct ia_css_frame *local_out_frame = NULL;
7793
7794                for (i = 0; i < num_primary_stage; i++) {
7795                        if (i == 0)
7796                                local_in_frame = in_frame;
7797                        else
7798                                local_in_frame = NULL;
7799#ifndef ISP2401
7800                        if (!need_pp && (i == num_primary_stage - 1))
7801#else
7802                        if (!need_pp && (i == num_primary_stage - 1) && !need_ldc)
7803#endif
7804                                local_out_frame = out_frame;
7805                        else
7806                                local_out_frame = NULL;
7807                        ia_css_pipe_util_set_output_frames(out_frames, 0, local_out_frame);
7808                        /*
7809                            * WARNING: The #if def flag has been added below as a
7810                            * temporary solution to solve the problem of enabling the
7811                            * view finder in a single binary in a capture flow. The
7812                            * vf-pp stage has been removed from Skycam in the solution
7813                            * provided. The vf-pp stage should be re-introduced when
7814                            * required. This  * should not be considered as a clean solution.
7815                            * Proper investigation should be done to come up with the clean
7816                            * solution.
7817                            * */
7818                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7819                                                           primary_binary[i],
7820                                                           out_frames,
7821                                                           local_in_frame,
7822                                                           NULL);
7823                        err = ia_css_pipeline_create_and_add_stage(me,
7824                                                                   &stage_desc,
7825                                                                   &current_stage);
7826                        if (err) {
7827                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7828                                return err;
7829                        }
7830                }
7831                /* If we use copy iso primary,
7832                    the input must be yuv iso raw */
7833                current_stage->args.copy_vf =
7834                    primary_binary[0]->info->sp.pipeline.mode ==
7835                    IA_CSS_BINARY_MODE_COPY;
7836                current_stage->args.copy_output = current_stage->args.copy_vf;
7837        } else if (mode == IA_CSS_CAPTURE_MODE_ADVANCED ||
7838                    mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
7839                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7840                ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
7841                                                   out_frames, in_frame, NULL);
7842                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7843                                                           NULL);
7844                if (err) {
7845                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7846                        return err;
7847                }
7848                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7849                ia_css_pipe_get_generic_stage_desc(&stage_desc, anr_gdc_binary,
7850                                                   out_frames, NULL, NULL);
7851                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7852                                                           NULL);
7853                if (err) {
7854                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7855                        return err;
7856                }
7857
7858                if (need_pp) {
7859                        ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7860                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7861                                                           post_isp_binary,
7862                                                           out_frames,
7863                                                           NULL, NULL);
7864                } else {
7865                        ia_css_pipe_util_set_output_frames(out_frames, 0,
7866                                                           out_frame);
7867                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7868                                                           post_isp_binary,
7869                                                           out_frames,
7870                                                           NULL, NULL);
7871                }
7872
7873                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7874                                                           &current_stage);
7875                if (err) {
7876                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7877                        return err;
7878                }
7879        } else if (mode == IA_CSS_CAPTURE_MODE_BAYER) {
7880                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7881                ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
7882                                                   out_frames, in_frame, NULL);
7883                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7884                                                           NULL);
7885                if (err) {
7886                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7887                        return err;
7888                }
7889        }
7890
7891#ifndef ISP2401
7892        if (need_pp && current_stage) {
7893                struct ia_css_frame *local_in_frame = NULL;
7894
7895                local_in_frame = current_stage->args.out_frame[0];
7896
7897                if (need_ldc) {
7898                        ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7899                        ia_css_pipe_get_generic_stage_desc(&stage_desc,
7900                                                           capture_ldc_binary,
7901                                                           out_frames,
7902                                                           local_in_frame,
7903                                                           NULL);
7904                        err = ia_css_pipeline_create_and_add_stage(me,
7905                                                                   &stage_desc,
7906                                                                   &current_stage);
7907                        local_in_frame = current_stage->args.out_frame[0];
7908                }
7909                err = add_capture_pp_stage(pipe, me, local_in_frame,
7910                                           need_yuv_pp ? NULL : out_frame,
7911#else
7912        /* ldc and capture_pp not supported in same pipeline */
7913        if (need_ldc && current_stage) {
7914                in_frame = current_stage->args.out_frame[0];
7915                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7916                ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_ldc_binary,
7917                                                   out_frames, in_frame, NULL);
7918                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7919                                                           NULL);
7920        } else if (need_pp && current_stage) {
7921                in_frame = current_stage->args.out_frame[0];
7922                err = add_capture_pp_stage(pipe, me, in_frame,
7923                                           need_yuv_pp ? NULL : out_frame,
7924#endif
7925                                           capture_pp_binary,
7926                                           &current_stage);
7927                if (err) {
7928                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7929                        return err;
7930                }
7931        }
7932
7933        if (need_yuv_pp && current_stage) {
7934                struct ia_css_frame *tmp_in_frame = current_stage->args.out_frame[0];
7935                struct ia_css_frame *tmp_out_frame = NULL;
7936
7937                for (i = 0; i < num_yuv_scaler; i++) {
7938                        if (is_output_stage[i])
7939                                tmp_out_frame = out_frame;
7940                        else
7941                                tmp_out_frame = NULL;
7942
7943                        err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
7944                                                   tmp_out_frame, NULL,
7945                                                   &yuv_scaler_binary[i],
7946                                                   &yuv_scaler_stage);
7947                        if (err) {
7948                                IA_CSS_LEAVE_ERR_PRIVATE(err);
7949                                return err;
7950                        }
7951                        /* we use output port 1 as internal output port */
7952                        tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
7953                }
7954        }
7955
7956        /*
7957            * WARNING: The #if def flag has been added below as a
7958            * temporary solution to solve the problem of enabling the
7959            * view finder in a single binary in a capture flow. The vf-pp
7960            * stage has been removed from Skycam in the solution provided.
7961            * The vf-pp stage should be re-introduced when required. This
7962            * should not be considered as a clean solution. Proper
7963            * investigation should be done to come up with the clean solution.
7964            * */
7965        if (mode != IA_CSS_CAPTURE_MODE_RAW &&
7966            mode != IA_CSS_CAPTURE_MODE_BAYER &&
7967            current_stage && vf_frame) {
7968                in_frame = current_stage->args.out_vf_frame;
7969                err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
7970                                      &current_stage);
7971                if (err) {
7972                        IA_CSS_LEAVE_ERR_PRIVATE(err);
7973                        return err;
7974                }
7975        }
7976        ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
7977
7978        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7979                            "create_host_regular_capture_pipeline() leave:\n");
7980
7981        return 0;
7982}
7983
7984static int
7985create_host_capture_pipeline(struct ia_css_pipe *pipe)
7986{
7987        int err = 0;
7988
7989        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7990
7991        if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
7992                err = create_host_isyscopy_capture_pipeline(pipe);
7993        else
7994                err = create_host_regular_capture_pipeline(pipe);
7995        if (err) {
7996                IA_CSS_LEAVE_ERR_PRIVATE(err);
7997                return err;
7998        }
7999
8000        IA_CSS_LEAVE_ERR_PRIVATE(err);
8001
8002        return err;
8003}
8004
8005static int capture_start(struct ia_css_pipe *pipe)
8006{
8007        struct ia_css_pipeline *me;
8008
8009        int err = 0;
8010        enum sh_css_pipe_config_override copy_ovrd;
8011
8012        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
8013        if (!pipe) {
8014                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8015                return -EINVAL;
8016        }
8017
8018        me = &pipe->pipeline;
8019
8020        if ((pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW   ||
8021             pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) &&
8022            (pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
8023                if (copy_on_sp(pipe)) {
8024                        err = start_copy_on_sp(pipe, &me->out_frame[0]);
8025                        IA_CSS_LEAVE_ERR_PRIVATE(err);
8026                        return err;
8027                }
8028        }
8029
8030#if !defined(ISP2401)
8031        /* old isys: need to send_mipi_frames() in all pipe modes */
8032        err = send_mipi_frames(pipe);
8033        if (err) {
8034                IA_CSS_LEAVE_ERR_PRIVATE(err);
8035                return err;
8036        }
8037#elif defined(ISP2401)
8038        if (pipe->config.mode != IA_CSS_PIPE_MODE_COPY) {
8039                err = send_mipi_frames(pipe);
8040                if (err) {
8041                        IA_CSS_LEAVE_ERR_PRIVATE(err);
8042                        return err;
8043                }
8044        }
8045
8046#endif
8047
8048        {
8049                unsigned int thread_id;
8050
8051                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
8052                copy_ovrd = 1 << thread_id;
8053        }
8054        start_pipe(pipe, copy_ovrd, pipe->stream->config.mode);
8055
8056#if !defined(ISP2401)
8057        /*
8058            * old isys: for IA_CSS_PIPE_MODE_COPY pipe, isys rx has to be configured,
8059            * which is currently done in start_binary(); but COPY pipe contains no binary,
8060            * and does not call start_binary(); so we need to configure the rx here.
8061            */
8062        if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY &&
8063            pipe->stream->reconfigure_css_rx) {
8064                ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
8065                                         pipe->stream->config.mode);
8066                pipe->stream->reconfigure_css_rx = false;
8067        }
8068#endif
8069
8070        IA_CSS_LEAVE_ERR_PRIVATE(err);
8071        return err;
8072}
8073
8074static int
8075sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
8076                                  struct ia_css_frame_info *info,
8077                                  unsigned int idx)
8078{
8079        assert(pipe);
8080        assert(info);
8081
8082        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8083                            "sh_css_pipe_get_output_frame_info() enter:\n");
8084
8085        *info = pipe->output_info[idx];
8086        if (copy_on_sp(pipe) &&
8087            pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
8088                ia_css_frame_info_init(
8089                    info,
8090                    JPEG_BYTES,
8091                    1,
8092                    IA_CSS_FRAME_FORMAT_BINARY_8,
8093                    0);
8094        } else if (info->format == IA_CSS_FRAME_FORMAT_RAW ||
8095                   info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) {
8096                info->raw_bit_depth =
8097                ia_css_pipe_util_pipe_input_format_bpp(pipe);
8098        }
8099
8100        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8101                            "sh_css_pipe_get_output_frame_info() leave:\n");
8102        return 0;
8103}
8104
8105void
8106ia_css_stream_send_input_frame(const struct ia_css_stream *stream,
8107                               const unsigned short *data,
8108                               unsigned int width,
8109                               unsigned int height)
8110{
8111        assert(stream);
8112
8113        ia_css_inputfifo_send_input_frame(
8114            data, width, height,
8115            stream->config.channel_id,
8116            stream->config.input_config.format,
8117            stream->config.pixels_per_clock == 2);
8118}
8119
8120void
8121ia_css_stream_start_input_frame(const struct ia_css_stream *stream)
8122{
8123        assert(stream);
8124
8125        ia_css_inputfifo_start_frame(
8126            stream->config.channel_id,
8127            stream->config.input_config.format,
8128            stream->config.pixels_per_clock == 2);
8129}
8130
8131void
8132ia_css_stream_send_input_line(const struct ia_css_stream *stream,
8133                              const unsigned short *data,
8134                              unsigned int width,
8135                              const unsigned short *data2,
8136                              unsigned int width2)
8137{
8138        assert(stream);
8139
8140        ia_css_inputfifo_send_line(stream->config.channel_id,
8141                                   data, width, data2, width2);
8142}
8143
8144void
8145ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream,
8146                                       enum atomisp_input_format format,
8147                                       const unsigned short *data,
8148                                       unsigned int width)
8149{
8150        assert(stream);
8151        if (!data || width == 0)
8152                return;
8153        ia_css_inputfifo_send_embedded_line(stream->config.channel_id,
8154                                            format, data, width);
8155}
8156
8157void
8158ia_css_stream_end_input_frame(const struct ia_css_stream *stream)
8159{
8160        assert(stream);
8161
8162        ia_css_inputfifo_end_frame(stream->config.channel_id);
8163}
8164
8165static void
8166append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
8167{
8168        IA_CSS_ENTER_PRIVATE("l = %p, firmware = %p", l, firmware);
8169        if (!l) {
8170                IA_CSS_ERROR("NULL fw_info");
8171                IA_CSS_LEAVE_PRIVATE("");
8172                return;
8173        }
8174        while (*l)
8175                l = &(*l)->next;
8176        *l = firmware;
8177        /*firmware->next = NULL;*/ /* when multiple acc extensions are loaded, 'next' can be not NULL */
8178        IA_CSS_LEAVE_PRIVATE("");
8179}
8180
8181static void
8182remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
8183{
8184        assert(*l);
8185        assert(firmware);
8186        (void)l;
8187        (void)firmware;
8188        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() enter:\n");
8189
8190        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() leave:\n");
8191        return; /* removing single and multiple firmware is handled in acc_unload_extension() */
8192}
8193
8194static int upload_isp_code(struct ia_css_fw_info *firmware)
8195{
8196        ia_css_ptr binary;
8197
8198        if (!firmware) {
8199                IA_CSS_ERROR("NULL input parameter");
8200                return -EINVAL;
8201        }
8202        binary = firmware->info.isp.xmem_addr;
8203
8204        if (!binary) {
8205                unsigned int size = firmware->blob.size;
8206                const unsigned char *blob;
8207                const unsigned char *binary_name;
8208
8209                binary_name =
8210                    (const unsigned char *)(IA_CSS_EXT_ISP_PROG_NAME(
8211                                                firmware));
8212                blob = binary_name +
8213                        strlen((const char *)binary_name) +
8214                        1;
8215                binary = sh_css_load_blob(blob, size);
8216                firmware->info.isp.xmem_addr = binary;
8217        }
8218
8219        if (!binary)
8220                return -ENOMEM;
8221        return 0;
8222}
8223
8224static int
8225acc_load_extension(struct ia_css_fw_info *firmware)
8226{
8227        int err;
8228        struct ia_css_fw_info *hd = firmware;
8229
8230        while (hd) {
8231                err = upload_isp_code(hd);
8232                if (err)
8233                        return err;
8234                hd = hd->next;
8235        }
8236
8237        if (!firmware)
8238                return -EINVAL;
8239        firmware->loaded = true;
8240        return 0;
8241}
8242
8243static void
8244acc_unload_extension(struct ia_css_fw_info *firmware)
8245{
8246        struct ia_css_fw_info *hd = firmware;
8247        struct ia_css_fw_info *hdn = NULL;
8248
8249        if (!firmware) /* should not happen */
8250                return;
8251        /* unload and remove multiple firmwares */
8252        while (hd) {
8253                hdn = (hd->next) ? &(*hd->next) : NULL;
8254                if (hd->info.isp.xmem_addr) {
8255                        hmm_free(hd->info.isp.xmem_addr);
8256                        hd->info.isp.xmem_addr = mmgr_NULL;
8257                }
8258                hd->isp_code = NULL;
8259                hd->next = NULL;
8260                hd = hdn;
8261        }
8262
8263        firmware->loaded = false;
8264}
8265
8266/* Load firmware for extension */
8267static int
8268ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
8269                           struct ia_css_fw_info *firmware)
8270{
8271        int err = 0;
8272
8273        IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
8274
8275        if ((!firmware) || (!pipe)) {
8276                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8277                return -EINVAL;
8278        }
8279
8280        if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT)
8281                append_firmware(&pipe->output_stage, firmware);
8282        else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER)
8283                append_firmware(&pipe->vf_stage, firmware);
8284        err = acc_load_extension(firmware);
8285
8286        IA_CSS_LEAVE_ERR_PRIVATE(err);
8287        return err;
8288}
8289
8290/* Unload firmware for extension */
8291static void
8292ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
8293                             struct ia_css_fw_info *firmware)
8294{
8295        IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
8296
8297        if ((!firmware) || (!pipe)) {
8298                IA_CSS_ERROR("NULL input parameters");
8299                IA_CSS_LEAVE_PRIVATE("");
8300                return;
8301        }
8302
8303        if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT)
8304                remove_firmware(&pipe->output_stage, firmware);
8305        else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER)
8306                remove_firmware(&pipe->vf_stage, firmware);
8307        acc_unload_extension(firmware);
8308
8309        IA_CSS_LEAVE_PRIVATE("");
8310}
8311
8312bool
8313ia_css_pipeline_uses_params(struct ia_css_pipeline *me)
8314{
8315        struct ia_css_pipeline_stage *stage;
8316
8317        assert(me);
8318
8319        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8320                            "ia_css_pipeline_uses_params() enter: me=%p\n", me);
8321
8322        for (stage = me->stages; stage; stage = stage->next)
8323                if (stage->binary_info && stage->binary_info->enable.params) {
8324                        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8325                                            "ia_css_pipeline_uses_params() leave: return_bool=true\n");
8326                        return true;
8327                }
8328        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8329                            "ia_css_pipeline_uses_params() leave: return_bool=false\n");
8330        return false;
8331}
8332
8333static int
8334sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
8335                              const void *acc_fw)
8336{
8337        struct ia_css_fw_info *fw = (struct ia_css_fw_info *)acc_fw;
8338        /* In QoS case, load_extension already called, so skipping */
8339        int     err = 0;
8340
8341        if (!fw->loaded)
8342                err = acc_load_extension(fw);
8343
8344        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8345                            "sh_css_pipeline_add_acc_stage() enter: pipeline=%p, acc_fw=%p\n",
8346                            pipeline, acc_fw);
8347
8348        if (!err) {
8349                struct ia_css_pipeline_stage_desc stage_desc;
8350
8351                ia_css_pipe_get_acc_stage_desc(&stage_desc, NULL, fw);
8352                err = ia_css_pipeline_create_and_add_stage(pipeline,
8353                                                           &stage_desc,
8354                                                           NULL);
8355        }
8356
8357        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8358                            "sh_css_pipeline_add_acc_stage() leave: return_err=%d\n", err);
8359        return err;
8360}
8361
8362/*
8363    * @brief Tag a specific frame in continuous capture.
8364    * Refer to "sh_css_internal.h" for details.
8365    */
8366int ia_css_stream_capture_frame(struct ia_css_stream *stream,
8367                                unsigned int exp_id)
8368{
8369        struct sh_css_tag_descr tag_descr;
8370        u32 encoded_tag_descr;
8371        int err;
8372
8373        assert(stream);
8374        IA_CSS_ENTER("exp_id=%d", exp_id);
8375
8376        /* Only continuous streams have a tagger */
8377        if (exp_id == 0 || !stream->config.continuous) {
8378                IA_CSS_LEAVE_ERR(-EINVAL);
8379                return -EINVAL;
8380        }
8381
8382        if (!sh_css_sp_is_running()) {
8383                /* SP is not running. The queues are not valid */
8384                IA_CSS_LEAVE_ERR(-EBUSY);
8385                return -EBUSY;
8386        }
8387
8388        /* Create the tag descriptor from the parameters */
8389        sh_css_create_tag_descr(0, 0, 0, exp_id, &tag_descr);
8390        /* Encode the tag descriptor into a 32-bit value */
8391        encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr);
8392        /* Enqueue the encoded tag to the host2sp queue.
8393            * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0
8394            * on both host and the SP side.
8395            * It is mainly because it is enough to have only one tag_cmd queue */
8396        err = ia_css_bufq_enqueue_tag_cmd(encoded_tag_descr);
8397
8398        IA_CSS_LEAVE_ERR(err);
8399        return err;
8400}
8401
8402/*
8403    * @brief Configure the continuous capture.
8404    * Refer to "sh_css_internal.h" for details.
8405    */
8406int ia_css_stream_capture(struct ia_css_stream *stream, int num_captures,
8407                          unsigned int skip, int offset)
8408{
8409        struct sh_css_tag_descr tag_descr;
8410        unsigned int encoded_tag_descr;
8411        int return_err;
8412
8413        if (!stream)
8414                return -EINVAL;
8415
8416        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8417                            "ia_css_stream_capture() enter: num_captures=%d, skip=%d, offset=%d\n",
8418                            num_captures, skip, offset);
8419
8420        /* Check if the tag descriptor is valid */
8421        if (num_captures < SH_CSS_MINIMUM_TAG_ID) {
8422                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8423                                    "ia_css_stream_capture() leave: return_err=%d\n",
8424                                    -EINVAL);
8425                return -EINVAL;
8426        }
8427
8428        /* Create the tag descriptor from the parameters */
8429        sh_css_create_tag_descr(num_captures, skip, offset, 0, &tag_descr);
8430
8431        /* Encode the tag descriptor into a 32-bit value */
8432        encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr);
8433
8434        if (!sh_css_sp_is_running()) {
8435                /* SP is not running. The queues are not valid */
8436                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8437                                    "ia_css_stream_capture() leaving:queues unavailable\n");
8438                return -EBUSY;
8439        }
8440
8441        /* Enqueue the encoded tag to the host2sp queue.
8442            * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0
8443            * on both host and the SP side.
8444            * It is mainly because it is enough to have only one tag_cmd queue */
8445        return_err = ia_css_bufq_enqueue_tag_cmd((uint32_t)encoded_tag_descr);
8446
8447        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8448                            "ia_css_stream_capture() leave: return_err=%d\n",
8449                            return_err);
8450
8451        return return_err;
8452}
8453
8454void ia_css_stream_request_flash(struct ia_css_stream *stream)
8455{
8456        (void)stream;
8457
8458        assert(stream);
8459        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8460                            "ia_css_stream_request_flash() enter: void\n");
8461
8462#ifndef ISP2401
8463        sh_css_write_host2sp_command(host2sp_cmd_start_flash);
8464#else
8465        if (sh_css_sp_is_running()) {
8466                if (!sh_css_write_host2sp_command(host2sp_cmd_start_flash)) {
8467                        IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed");
8468                        ia_css_debug_dump_sp_sw_debug_info();
8469                        ia_css_debug_dump_debug_info(NULL);
8470                }
8471        } else {
8472                IA_CSS_LOG("SP is not running!");
8473        }
8474
8475#endif
8476        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8477                            "ia_css_stream_request_flash() leave: return_void\n");
8478}
8479
8480static void
8481sh_css_init_host_sp_control_vars(void)
8482{
8483        const struct ia_css_fw_info *fw;
8484        unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started;
8485
8486        unsigned int HIVE_ADDR_host_sp_queues_initialized;
8487        unsigned int HIVE_ADDR_sp_sleep_mode;
8488        unsigned int HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb;
8489#ifndef ISP2401
8490        unsigned int HIVE_ADDR_sp_stop_copy_preview;
8491#endif
8492        unsigned int HIVE_ADDR_host_sp_com;
8493        unsigned int o = offsetof(struct host_sp_communication, host2sp_command)
8494                            / sizeof(int);
8495
8496        unsigned int i;
8497
8498        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8499                            "sh_css_init_host_sp_control_vars() enter: void\n");
8500
8501        fw = &sh_css_sp_fw;
8502        HIVE_ADDR_ia_css_ispctrl_sp_isp_started = fw->info.sp.isp_started;
8503
8504        HIVE_ADDR_host_sp_queues_initialized =
8505            fw->info.sp.host_sp_queues_initialized;
8506        HIVE_ADDR_sp_sleep_mode = fw->info.sp.sleep_mode;
8507        HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb = fw->info.sp.invalidate_tlb;
8508#ifndef ISP2401
8509        HIVE_ADDR_sp_stop_copy_preview = fw->info.sp.stop_copy_preview;
8510#endif
8511        HIVE_ADDR_host_sp_com = fw->info.sp.host_sp_com;
8512
8513        (void)HIVE_ADDR_ia_css_ispctrl_sp_isp_started; /* Suppres warnings in CRUN */
8514
8515        (void)HIVE_ADDR_sp_sleep_mode;
8516        (void)HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb;
8517#ifndef ISP2401
8518        (void)HIVE_ADDR_sp_stop_copy_preview;
8519#endif
8520        (void)HIVE_ADDR_host_sp_com;
8521
8522        sp_dmem_store_uint32(SP0_ID,
8523                             (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started),
8524                             (uint32_t)(0));
8525
8526        sp_dmem_store_uint32(SP0_ID,
8527                             (unsigned int)sp_address_of(host_sp_queues_initialized),
8528                             (uint32_t)(0));
8529        sp_dmem_store_uint32(SP0_ID,
8530                             (unsigned int)sp_address_of(sp_sleep_mode),
8531                             (uint32_t)(0));
8532        sp_dmem_store_uint32(SP0_ID,
8533                             (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb),
8534                             (uint32_t)(false));
8535#ifndef ISP2401
8536        sp_dmem_store_uint32(SP0_ID,
8537                             (unsigned int)sp_address_of(sp_stop_copy_preview),
8538                             my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0));
8539#endif
8540        store_sp_array_uint(host_sp_com, o, host2sp_cmd_ready);
8541
8542        for (i = 0; i < N_CSI_PORTS; i++) {
8543                sh_css_update_host2sp_num_mipi_frames
8544                (my_css.num_mipi_frames[i]);
8545        }
8546
8547        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8548                            "sh_css_init_host_sp_control_vars() leave: return_void\n");
8549}
8550
8551/*
8552 * create the internal structures and fill in the configuration data
8553 */
8554
8555static const struct
8556ia_css_pipe_config ia_css_pipe_default_config = DEFAULT_PIPE_CONFIG;
8557
8558void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config)
8559{
8560        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_config_defaults()\n");
8561        memcpy(pipe_config, &ia_css_pipe_default_config, sizeof(*pipe_config));
8562}
8563
8564void
8565ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config *extra_config)
8566{
8567        if (!extra_config) {
8568                IA_CSS_ERROR("NULL input parameter");
8569                return;
8570        }
8571
8572        extra_config->enable_raw_binning = false;
8573        extra_config->enable_yuv_ds = false;
8574        extra_config->enable_high_speed = false;
8575        extra_config->enable_dvs_6axis = false;
8576        extra_config->enable_reduced_pipe = false;
8577        extra_config->disable_vf_pp = false;
8578        extra_config->enable_fractional_ds = false;
8579}
8580
8581void ia_css_stream_config_defaults(struct ia_css_stream_config *stream_config)
8582{
8583        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_config_defaults()\n");
8584        assert(stream_config);
8585        memset(stream_config, 0, sizeof(*stream_config));
8586        stream_config->online = true;
8587        stream_config->left_padding = -1;
8588        stream_config->pixels_per_clock = 1;
8589        /* temporary default value for backwards compatibility.
8590            * This field used to be hardcoded within CSS but this has now
8591            * been moved to the stream_config struct. */
8592        stream_config->source.port.rxcount = 0x04040404;
8593}
8594
8595static int
8596ia_css_acc_pipe_create(struct ia_css_pipe *pipe)
8597{
8598        int err = 0;
8599
8600        if (!pipe) {
8601                IA_CSS_ERROR("NULL input parameter");
8602                return -EINVAL;
8603        }
8604
8605        /* There is not meaning for num_execs = 0 semantically. Run atleast once. */
8606        if (pipe->config.acc_num_execs == 0)
8607                pipe->config.acc_num_execs = 1;
8608
8609        if (pipe->config.acc_extension)
8610                err = ia_css_pipe_load_extension(pipe, pipe->config.acc_extension);
8611
8612        return err;
8613}
8614
8615int ia_css_pipe_create(const struct ia_css_pipe_config *config,
8616                       struct ia_css_pipe **pipe)
8617{
8618        int err = 0;
8619
8620        IA_CSS_ENTER_PRIVATE("config = %p, pipe = %p", config, pipe);
8621
8622        if (!config || !pipe) {
8623                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8624                return -EINVAL;
8625        }
8626
8627        err = ia_css_pipe_create_extra(config, NULL, pipe);
8628
8629        if (err == 0)
8630                IA_CSS_LOG("pipe created successfully = %p", *pipe);
8631
8632        IA_CSS_LEAVE_ERR_PRIVATE(err);
8633
8634        return err;
8635}
8636
8637int
8638ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
8639                         const struct ia_css_pipe_extra_config *extra_config,
8640                         struct ia_css_pipe **pipe)
8641{
8642        int err = -EINVAL;
8643        struct ia_css_pipe *internal_pipe = NULL;
8644        unsigned int i;
8645
8646        IA_CSS_ENTER_PRIVATE("config = %p, extra_config = %p and pipe = %p", config, extra_config, pipe);
8647
8648        /* do not allow to create more than the maximum limit */
8649        if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX) {
8650                IA_CSS_LEAVE_ERR_PRIVATE(-ENOSPC);
8651                return -EINVAL;
8652        }
8653
8654        if ((!pipe) || (!config)) {
8655                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8656                return -EINVAL;
8657        }
8658
8659        ia_css_debug_dump_pipe_config(config);
8660        ia_css_debug_dump_pipe_extra_config(extra_config);
8661
8662        err = create_pipe(config->mode, &internal_pipe, false);
8663        if (err) {
8664                IA_CSS_LEAVE_ERR_PRIVATE(err);
8665                return err;
8666        }
8667
8668        /* now we have a pipe structure to fill */
8669        internal_pipe->config = *config;
8670        if (extra_config)
8671                internal_pipe->extra_config = *extra_config;
8672        else
8673                ia_css_pipe_extra_config_defaults(&internal_pipe->extra_config);
8674
8675        if (config->mode == IA_CSS_PIPE_MODE_ACC) {
8676                /* Temporary hack to migrate acceleration to CSS 2.0.
8677                    * In the future the code for all pipe types should be
8678                    * unified. */
8679                *pipe = internal_pipe;
8680                if (!internal_pipe->config.acc_extension &&
8681                    internal_pipe->config.num_acc_stages ==
8682                    0) { /* if no acc binary and no standalone stage */
8683                        *pipe = NULL;
8684                        IA_CSS_LEAVE_ERR_PRIVATE(0);
8685                        return 0;
8686                }
8687                return ia_css_acc_pipe_create(internal_pipe);
8688        }
8689
8690        /* Use config value when dvs_frame_delay setting equal to 2, otherwise always 1 by default */
8691        if (internal_pipe->config.dvs_frame_delay == IA_CSS_FRAME_DELAY_2)
8692                internal_pipe->dvs_frame_delay = 2;
8693        else
8694                internal_pipe->dvs_frame_delay = 1;
8695
8696        /* we still keep enable_raw_binning for backward compatibility, for any new
8697            fractional bayer downscaling, we should use bayer_ds_out_res. if both are
8698            specified, bayer_ds_out_res will take precedence.if none is specified, we
8699            set bayer_ds_out_res equal to IF output resolution(IF may do cropping on
8700            sensor output) or use default decimation factor 1. */
8701        if (internal_pipe->extra_config.enable_raw_binning &&
8702            internal_pipe->config.bayer_ds_out_res.width) {
8703                /* fill some code here, if no code is needed, please remove it during integration */
8704        }
8705
8706        /* YUV downscaling */
8707        if ((internal_pipe->config.vf_pp_in_res.width ||
8708             internal_pipe->config.capt_pp_in_res.width)) {
8709                enum ia_css_frame_format format;
8710
8711                if (internal_pipe->config.vf_pp_in_res.width) {
8712                        format = IA_CSS_FRAME_FORMAT_YUV_LINE;
8713                        ia_css_frame_info_init(
8714                            &internal_pipe->vf_yuv_ds_input_info,
8715                            internal_pipe->config.vf_pp_in_res.width,
8716                            internal_pipe->config.vf_pp_in_res.height,
8717                            format, 0);
8718                }
8719                if (internal_pipe->config.capt_pp_in_res.width) {
8720                        format = IA_CSS_FRAME_FORMAT_YUV420;
8721                        ia_css_frame_info_init(
8722                            &internal_pipe->out_yuv_ds_input_info,
8723                            internal_pipe->config.capt_pp_in_res.width,
8724                            internal_pipe->config.capt_pp_in_res.height,
8725                            format, 0);
8726                }
8727        }
8728        if (internal_pipe->config.vf_pp_in_res.width &&
8729            internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) {
8730                ia_css_frame_info_init(
8731                    &internal_pipe->vf_yuv_ds_input_info,
8732                    internal_pipe->config.vf_pp_in_res.width,
8733                    internal_pipe->config.vf_pp_in_res.height,
8734                    IA_CSS_FRAME_FORMAT_YUV_LINE, 0);
8735        }
8736        /* handle bayer downscaling output info */
8737        if (internal_pipe->config.bayer_ds_out_res.width) {
8738                ia_css_frame_info_init(
8739                    &internal_pipe->bds_output_info,
8740                    internal_pipe->config.bayer_ds_out_res.width,
8741                    internal_pipe->config.bayer_ds_out_res.height,
8742                    IA_CSS_FRAME_FORMAT_RAW, 0);
8743        }
8744
8745        /* handle output info, assume always needed */
8746        for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
8747                if (internal_pipe->config.output_info[i].res.width) {
8748                        err = sh_css_pipe_configure_output(
8749                                    internal_pipe,
8750                                    internal_pipe->config.output_info[i].res.width,
8751                                    internal_pipe->config.output_info[i].res.height,
8752                                    internal_pipe->config.output_info[i].padded_width,
8753                                    internal_pipe->config.output_info[i].format,
8754                                    i);
8755                        if (err) {
8756                                IA_CSS_LEAVE_ERR_PRIVATE(err);
8757                                kvfree(internal_pipe);
8758                                internal_pipe = NULL;
8759                                return err;
8760                        }
8761                }
8762
8763                /* handle vf output info, when configured */
8764                internal_pipe->enable_viewfinder[i] =
8765                    (internal_pipe->config.vf_output_info[i].res.width != 0);
8766                if (internal_pipe->config.vf_output_info[i].res.width) {
8767                        err = sh_css_pipe_configure_viewfinder(
8768                                    internal_pipe,
8769                                    internal_pipe->config.vf_output_info[i].res.width,
8770                                    internal_pipe->config.vf_output_info[i].res.height,
8771                                    internal_pipe->config.vf_output_info[i].padded_width,
8772                                    internal_pipe->config.vf_output_info[i].format,
8773                                    i);
8774                        if (err) {
8775                                IA_CSS_LEAVE_ERR_PRIVATE(err);
8776                                kvfree(internal_pipe);
8777                                internal_pipe = NULL;
8778                                return err;
8779                        }
8780                }
8781        }
8782        if (internal_pipe->config.acc_extension) {
8783                err = ia_css_pipe_load_extension(internal_pipe,
8784                                                 internal_pipe->config.acc_extension);
8785                if (err) {
8786                        IA_CSS_LEAVE_ERR_PRIVATE(err);
8787                        kvfree(internal_pipe);
8788                        return err;
8789                }
8790        }
8791        /* set all info to zeroes first */
8792        memset(&internal_pipe->info, 0, sizeof(internal_pipe->info));
8793
8794        /* all went well, return the pipe */
8795        *pipe = internal_pipe;
8796        IA_CSS_LEAVE_ERR_PRIVATE(0);
8797        return 0;
8798}
8799
8800int
8801ia_css_pipe_get_info(const struct ia_css_pipe *pipe,
8802                     struct ia_css_pipe_info *pipe_info)
8803{
8804        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8805                            "ia_css_pipe_get_info()\n");
8806        if (!pipe_info) {
8807                ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
8808                                    "ia_css_pipe_get_info: pipe_info cannot be NULL\n");
8809                return -EINVAL;
8810        }
8811        if (!pipe || !pipe->stream) {
8812                ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
8813                                    "ia_css_pipe_get_info: ia_css_stream_create needs to be called before ia_css_[stream/pipe]_get_info\n");
8814                return -EINVAL;
8815        }
8816        /* we succeeded return the info */
8817        *pipe_info = pipe->info;
8818        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_get_info() leave\n");
8819        return 0;
8820}
8821
8822bool ia_css_pipe_has_dvs_stats(struct ia_css_pipe_info *pipe_info)
8823{
8824        unsigned int i;
8825
8826        if (pipe_info) {
8827                for (i = 0; i < IA_CSS_DVS_STAT_NUM_OF_LEVELS; i++) {
8828                        if (pipe_info->grid_info.dvs_grid.dvs_stat_grid_info.grd_cfg[i].grd_start.enable)
8829                                return true;
8830                }
8831        }
8832
8833        return false;
8834}
8835
8836int
8837ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe,
8838                                  int pin_index,
8839                                  enum ia_css_frame_format new_format)
8840{
8841        int err = 0;
8842
8843        IA_CSS_ENTER_PRIVATE("pipe = %p, pin_index = %d, new_formats = %d", pipe, pin_index, new_format);
8844
8845        if (!pipe) {
8846                IA_CSS_ERROR("pipe is not set");
8847                err = -EINVAL;
8848                IA_CSS_LEAVE_ERR_PRIVATE(err);
8849                return err;
8850        }
8851        if (0 != pin_index && 1 != pin_index) {
8852                IA_CSS_ERROR("pin index is not valid");
8853                err = -EINVAL;
8854                IA_CSS_LEAVE_ERR_PRIVATE(err);
8855                return err;
8856        }
8857        if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY) {
8858                IA_CSS_ERROR("new format is not valid");
8859                err = -EINVAL;
8860                IA_CSS_LEAVE_ERR_PRIVATE(err);
8861                return err;
8862        } else {
8863                err = ia_css_pipe_check_format(pipe, new_format);
8864                if (!err) {
8865                        if (pin_index == 0)
8866                                pipe->output_info[0].format = new_format;
8867                        else
8868                                pipe->vf_output_info[0].format = new_format;
8869                }
8870        }
8871        IA_CSS_LEAVE_ERR_PRIVATE(err);
8872        return err;
8873}
8874
8875#if !defined(ISP2401)
8876/* Configuration of INPUT_SYSTEM_VERSION_2401 is done on SP */
8877static int
8878ia_css_stream_configure_rx(struct ia_css_stream *stream)
8879{
8880        struct ia_css_input_port *config;
8881
8882        assert(stream);
8883
8884        config = &stream->config.source.port;
8885        /* AM: this code is not reliable, especially for 2400 */
8886        if (config->num_lanes == 1)
8887                stream->csi_rx_config.mode = MONO_1L_1L_0L;
8888        else if (config->num_lanes == 2)
8889                stream->csi_rx_config.mode = MONO_2L_1L_0L;
8890        else if (config->num_lanes == 3)
8891                stream->csi_rx_config.mode = MONO_3L_1L_0L;
8892        else if (config->num_lanes == 4)
8893                stream->csi_rx_config.mode = MONO_4L_1L_0L;
8894        else if (config->num_lanes != 0)
8895                return -EINVAL;
8896
8897        if (config->port > MIPI_PORT2_ID)
8898                return -EINVAL;
8899        stream->csi_rx_config.port =
8900        ia_css_isys_port_to_mipi_port(config->port);
8901        stream->csi_rx_config.timeout    = config->timeout;
8902        stream->csi_rx_config.initcount  = 0;
8903        stream->csi_rx_config.synccount  = 0x28282828;
8904        stream->csi_rx_config.rxcount    = config->rxcount;
8905        if (config->compression.type == IA_CSS_CSI2_COMPRESSION_TYPE_NONE)
8906                stream->csi_rx_config.comp = MIPI_PREDICTOR_NONE;
8907        else
8908                /* not implemented yet, requires extension of the rx_cfg_t
8909                    * struct */
8910                return -EINVAL;
8911
8912        stream->csi_rx_config.is_two_ppc = (stream->config.pixels_per_clock == 2);
8913        stream->reconfigure_css_rx = true;
8914        return 0;
8915}
8916#endif
8917
8918static struct ia_css_pipe *
8919find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes,
8920          enum ia_css_pipe_mode mode, bool copy_pipe)
8921{
8922        unsigned int i;
8923
8924        assert(pipes);
8925        for (i = 0; i < num_pipes; i++) {
8926                assert(pipes[i]);
8927                if (pipes[i]->config.mode != mode)
8928                        continue;
8929                if (copy_pipe && pipes[i]->mode != IA_CSS_PIPE_ID_COPY)
8930                        continue;
8931                return pipes[i];
8932        }
8933        return NULL;
8934}
8935
8936static int
8937ia_css_acc_stream_create(struct ia_css_stream *stream)
8938{
8939        int i;
8940        int err = 0;
8941
8942        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
8943
8944        if (!stream) {
8945                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8946                return -EINVAL;
8947        }
8948
8949        for (i = 0;  i < stream->num_pipes; i++) {
8950                struct ia_css_pipe *pipe = stream->pipes[i];
8951
8952                if (!pipe) {
8953                        IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8954                        return -EINVAL;
8955                }
8956
8957                pipe->stream = stream;
8958        }
8959
8960        /* Map SP threads before doing anything. */
8961        err = map_sp_threads(stream, true);
8962        if (err) {
8963                IA_CSS_LEAVE_ERR_PRIVATE(err);
8964                return err;
8965        }
8966
8967        for (i = 0;  i < stream->num_pipes; i++) {
8968                struct ia_css_pipe *pipe = stream->pipes[i];
8969
8970                assert(pipe);
8971                ia_css_pipe_map_queue(pipe, true);
8972        }
8973
8974        err = create_host_pipeline_structure(stream);
8975        if (err) {
8976                IA_CSS_LEAVE_ERR_PRIVATE(err);
8977                return err;
8978        }
8979
8980        stream->started = false;
8981
8982        IA_CSS_LEAVE_ERR_PRIVATE(0);
8983
8984        return 0;
8985}
8986
8987static int
8988metadata_info_init(const struct ia_css_metadata_config *mdc,
8989                   struct ia_css_metadata_info *md)
8990{
8991        /* Either both width and height should be set or neither */
8992        if ((mdc->resolution.height > 0) ^ (mdc->resolution.width > 0))
8993                return -EINVAL;
8994
8995        md->resolution = mdc->resolution;
8996        /* We round up the stride to a multiple of the width
8997            * of the port going to DDR, this is a HW requirements (DMA). */
8998        md->stride = CEIL_MUL(mdc->resolution.width, HIVE_ISP_DDR_WORD_BYTES);
8999        md->size = mdc->resolution.height * md->stride;
9000        return 0;
9001}
9002
9003/* ISP2401 */
9004static int check_pipe_resolutions(const struct ia_css_pipe *pipe)
9005{
9006        int err = 0;
9007
9008        IA_CSS_ENTER_PRIVATE("");
9009
9010        if (!pipe || !pipe->stream) {
9011                IA_CSS_ERROR("null arguments");
9012                err = -EINVAL;
9013                goto EXIT;
9014        }
9015
9016        if (ia_css_util_check_res(pipe->config.input_effective_res.width,
9017                                  pipe->config.input_effective_res.height) != 0) {
9018                IA_CSS_ERROR("effective resolution not supported");
9019                err = -EINVAL;
9020                goto EXIT;
9021        }
9022        if (!ia_css_util_resolution_is_zero(
9023                pipe->stream->config.input_config.input_res)) {
9024                if (!ia_css_util_res_leq(pipe->config.input_effective_res,
9025                                         pipe->stream->config.input_config.input_res)) {
9026                        IA_CSS_ERROR("effective resolution is larger than input resolution");
9027                        err = -EINVAL;
9028                        goto EXIT;
9029                }
9030        }
9031        if (!ia_css_util_resolution_is_even(pipe->config.output_info[0].res)) {
9032                IA_CSS_ERROR("output resolution must be even");
9033                err = -EINVAL;
9034                goto EXIT;
9035        }
9036        if (!ia_css_util_resolution_is_even(pipe->config.vf_output_info[0].res)) {
9037                IA_CSS_ERROR("VF resolution must be even");
9038                err = -EINVAL;
9039                goto EXIT;
9040        }
9041EXIT:
9042        IA_CSS_LEAVE_ERR_PRIVATE(err);
9043        return err;
9044}
9045
9046int
9047ia_css_stream_create(const struct ia_css_stream_config *stream_config,
9048                     int num_pipes,
9049                     struct ia_css_pipe *pipes[],
9050                     struct ia_css_stream **stream)
9051{
9052        struct ia_css_pipe *curr_pipe;
9053        struct ia_css_stream *curr_stream = NULL;
9054        bool spcopyonly;
9055        bool sensor_binning_changed;
9056        int i, j;
9057        int err = -EINVAL;
9058        struct ia_css_metadata_info md_info;
9059        struct ia_css_resolution effective_res;
9060#ifdef ISP2401
9061        bool aspect_ratio_crop_enabled = false;
9062#endif
9063
9064        IA_CSS_ENTER("num_pipes=%d", num_pipes);
9065        ia_css_debug_dump_stream_config(stream_config, num_pipes);
9066
9067        /* some checks */
9068        if (num_pipes == 0 ||
9069            !stream ||
9070            !pipes) {
9071                err = -EINVAL;
9072                IA_CSS_LEAVE_ERR(err);
9073                return err;
9074        }
9075
9076#if !defined(ISP2401)
9077        /* We don't support metadata for JPEG stream, since they both use str2mem */
9078        if (stream_config->input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8 &&
9079            stream_config->metadata_config.resolution.height > 0) {
9080                err = -EINVAL;
9081                IA_CSS_LEAVE_ERR(err);
9082                return err;
9083        }
9084#endif
9085
9086#ifdef ISP2401
9087        if (stream_config->online && stream_config->pack_raw_pixels) {
9088                IA_CSS_LOG("online and pack raw is invalid on input system 2401");
9089                err = -EINVAL;
9090                IA_CSS_LEAVE_ERR(err);
9091                return err;
9092        }
9093#endif
9094
9095        ia_css_debug_pipe_graph_dump_stream_config(stream_config);
9096
9097        /* check if mipi size specified */
9098        if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
9099#ifdef ISP2401
9100                if (!stream_config->online)
9101#endif
9102                {
9103                        unsigned int port = (unsigned int)stream_config->source.port.port;
9104
9105                        if (port >= N_MIPI_PORT_ID) {
9106                                err = -EINVAL;
9107                                IA_CSS_LEAVE_ERR(err);
9108                                return err;
9109                        }
9110
9111                        if (my_css.size_mem_words != 0) {
9112                                my_css.mipi_frame_size[port] = my_css.size_mem_words;
9113                        } else if (stream_config->mipi_buffer_config.size_mem_words != 0) {
9114                                my_css.mipi_frame_size[port] = stream_config->mipi_buffer_config.size_mem_words;
9115                        } else {
9116                                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9117                                                    "ia_css_stream_create() exit: error, need to set mipi frame size.\n");
9118                                assert(stream_config->mipi_buffer_config.size_mem_words != 0);
9119                                err = -EINVAL;
9120                                IA_CSS_LEAVE_ERR(err);
9121                                return err;
9122                        }
9123
9124                        if (my_css.size_mem_words != 0) {
9125                                my_css.num_mipi_frames[port] =
9126                                    2; /* Temp change: Default for backwards compatibility. */
9127                        } else if (stream_config->mipi_buffer_config.nof_mipi_buffers != 0) {
9128                                my_css.num_mipi_frames[port] =
9129                                    stream_config->mipi_buffer_config.nof_mipi_buffers;
9130                        } else {
9131                                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9132                                                    "ia_css_stream_create() exit: error, need to set number of mipi frames.\n");
9133                                assert(stream_config->mipi_buffer_config.nof_mipi_buffers != 0);
9134                                err = -EINVAL;
9135                                IA_CSS_LEAVE_ERR(err);
9136                                return err;
9137                        }
9138                }
9139
9140        /* Currently we only supported metadata up to a certain size. */
9141        err = metadata_info_init(&stream_config->metadata_config, &md_info);
9142        if (err) {
9143                IA_CSS_LEAVE_ERR(err);
9144                return err;
9145        }
9146
9147        /* allocate the stream instance */
9148        curr_stream = kzalloc(sizeof(struct ia_css_stream), GFP_KERNEL);
9149        if (!curr_stream) {
9150                err = -ENOMEM;
9151                IA_CSS_LEAVE_ERR(err);
9152                return err;
9153        }
9154        /* default all to 0 */
9155        curr_stream->info.metadata_info = md_info;
9156
9157        /* allocate pipes */
9158        curr_stream->num_pipes = num_pipes;
9159        curr_stream->pipes = kcalloc(num_pipes, sizeof(struct ia_css_pipe *), GFP_KERNEL);
9160        if (!curr_stream->pipes) {
9161                curr_stream->num_pipes = 0;
9162                kfree(curr_stream);
9163                curr_stream = NULL;
9164                err = -ENOMEM;
9165                IA_CSS_LEAVE_ERR(err);
9166                return err;
9167        }
9168        /* store pipes */
9169        spcopyonly = (num_pipes == 1) && (pipes[0]->config.mode == IA_CSS_PIPE_MODE_COPY);
9170        for (i = 0; i < num_pipes; i++)
9171                curr_stream->pipes[i] = pipes[i];
9172        curr_stream->last_pipe = curr_stream->pipes[0];
9173        /* take over stream config */
9174        curr_stream->config = *stream_config;
9175
9176#if defined(ISP2401)
9177        if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR &&
9178            stream_config->online)
9179                curr_stream->config.online = false;
9180#endif
9181
9182#ifdef ISP2401
9183        if (curr_stream->config.online) {
9184                curr_stream->config.source.port.num_lanes =
9185                    stream_config->source.port.num_lanes;
9186                curr_stream->config.mode =  IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
9187        }
9188#endif
9189        /* in case driver doesn't configure init number of raw buffers, configure it here */
9190        if (curr_stream->config.target_num_cont_raw_buf == 0)
9191                curr_stream->config.target_num_cont_raw_buf = NUM_CONTINUOUS_FRAMES;
9192        if (curr_stream->config.init_num_cont_raw_buf == 0)
9193                curr_stream->config.init_num_cont_raw_buf = curr_stream->config.target_num_cont_raw_buf;
9194
9195        /* Enable locking & unlocking of buffers in RAW buffer pool */
9196        if (curr_stream->config.ia_css_enable_raw_buffer_locking)
9197                sh_css_sp_configure_enable_raw_pool_locking(
9198                    curr_stream->config.lock_all);
9199
9200        /* copy mode specific stuff */
9201        switch (curr_stream->config.mode) {
9202        case IA_CSS_INPUT_MODE_SENSOR:
9203        case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
9204#if !defined(ISP2401)
9205                ia_css_stream_configure_rx(curr_stream);
9206#endif
9207                break;
9208        case IA_CSS_INPUT_MODE_TPG:
9209#if !defined(ISP2401)
9210                IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d",
9211                           curr_stream->config.source.tpg.x_mask,
9212                           curr_stream->config.source.tpg.y_mask,
9213                           curr_stream->config.source.tpg.x_delta,
9214                           curr_stream->config.source.tpg.y_delta,
9215                           curr_stream->config.source.tpg.xy_mask);
9216
9217                sh_css_sp_configure_tpg(
9218                    curr_stream->config.source.tpg.x_mask,
9219                    curr_stream->config.source.tpg.y_mask,
9220                    curr_stream->config.source.tpg.x_delta,
9221                    curr_stream->config.source.tpg.y_delta,
9222                    curr_stream->config.source.tpg.xy_mask);
9223#endif
9224                break;
9225        case IA_CSS_INPUT_MODE_PRBS:
9226#if !defined(ISP2401)
9227                IA_CSS_LOG("mode prbs");
9228                sh_css_sp_configure_prbs(curr_stream->config.source.prbs.seed);
9229#endif
9230                break;
9231        case IA_CSS_INPUT_MODE_MEMORY:
9232                IA_CSS_LOG("mode memory");
9233                curr_stream->reconfigure_css_rx = false;
9234                break;
9235        default:
9236                IA_CSS_LOG("mode sensor/default");
9237        }
9238
9239#ifdef ISP2401
9240        err = aspect_ratio_crop_init(curr_stream, pipes,
9241                                     &aspect_ratio_crop_enabled);
9242        if (err) {
9243                IA_CSS_LEAVE_ERR(err);
9244                goto ERR;
9245        }
9246#endif
9247        for (i = 0; i < num_pipes; i++) {
9248                struct ia_css_resolution effective_res;
9249
9250                curr_pipe = pipes[i];
9251                /* set current stream */
9252                curr_pipe->stream = curr_stream;
9253                /* take over effective info */
9254
9255                effective_res = curr_pipe->config.input_effective_res;
9256                if (effective_res.height == 0 || effective_res.width == 0) {
9257                        effective_res = curr_pipe->stream->config.input_config.effective_res;
9258
9259#if defined(ISP2401)
9260                        /* The aspect ratio cropping is currently only
9261                            * supported on the new input system. */
9262                        if (aspect_ratio_crop_check(aspect_ratio_crop_enabled, curr_pipe)) {
9263                                struct ia_css_resolution crop_res;
9264
9265                                err = aspect_ratio_crop(curr_pipe, &crop_res);
9266                                if (!err) {
9267                                        effective_res = crop_res;
9268                                } else {
9269                                        /* in case of error fallback to default
9270                                            * effective resolution from driver. */
9271                                        IA_CSS_LOG("aspect_ratio_crop() failed with err(%d)", err);
9272                                }
9273                        }
9274#endif
9275                        curr_pipe->config.input_effective_res = effective_res;
9276                }
9277                IA_CSS_LOG("effective_res=%dx%d",
9278                           effective_res.width,
9279                           effective_res.height);
9280        }
9281
9282        if (IS_ISP2401) {
9283                for (i = 0; i < num_pipes; i++) {
9284                        if (pipes[i]->config.mode != IA_CSS_PIPE_MODE_ACC &&
9285                            pipes[i]->config.mode != IA_CSS_PIPE_MODE_COPY) {
9286                                err = check_pipe_resolutions(pipes[i]);
9287                                if (err)
9288                                        goto ERR;
9289                        }
9290                }
9291        }
9292
9293        err = ia_css_stream_isp_parameters_init(curr_stream);
9294        if (err)
9295                goto ERR;
9296        IA_CSS_LOG("isp_params_configs: %p", curr_stream->isp_params_configs);
9297
9298        if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC) {
9299                *stream = curr_stream;
9300                err = ia_css_acc_stream_create(curr_stream);
9301                goto ERR;
9302        }
9303        /* sensor binning */
9304        if (!spcopyonly) {
9305                sensor_binning_changed =
9306                    sh_css_params_set_binning_factor(curr_stream,
9307                                                     curr_stream->config.sensor_binning_factor);
9308        } else {
9309                sensor_binning_changed = false;
9310        }
9311
9312        IA_CSS_LOG("sensor_binning=%d, changed=%d",
9313                   curr_stream->config.sensor_binning_factor, sensor_binning_changed);
9314        /* loop over pipes */
9315        IA_CSS_LOG("num_pipes=%d", num_pipes);
9316        curr_stream->cont_capt = false;
9317        /* Temporary hack: we give the preview pipe a reference to the capture
9318            * pipe in continuous capture mode. */
9319        if (curr_stream->config.continuous) {
9320                /* Search for the preview pipe and create the copy pipe */
9321                struct ia_css_pipe *preview_pipe;
9322                struct ia_css_pipe *video_pipe;
9323                struct ia_css_pipe *acc_pipe;
9324                struct ia_css_pipe *capture_pipe = NULL;
9325                struct ia_css_pipe *copy_pipe = NULL;
9326
9327                if (num_pipes >= 2) {
9328                        curr_stream->cont_capt = true;
9329                        curr_stream->disable_cont_vf = curr_stream->config.disable_cont_viewfinder;
9330
9331                        if (!IS_ISP2401)
9332                                curr_stream->stop_copy_preview = my_css.stop_copy_preview;
9333                }
9334
9335                /* Create copy pipe here, since it may not be exposed to the driver */
9336                preview_pipe = find_pipe(pipes, num_pipes,
9337                                         IA_CSS_PIPE_MODE_PREVIEW, false);
9338                video_pipe = find_pipe(pipes, num_pipes,
9339                                       IA_CSS_PIPE_MODE_VIDEO, false);
9340                acc_pipe = find_pipe(pipes, num_pipes, IA_CSS_PIPE_MODE_ACC,
9341                                     false);
9342                if (acc_pipe && num_pipes == 2 && curr_stream->cont_capt)
9343                        curr_stream->cont_capt =
9344                            false; /* preview + QoS case will not need cont_capt switch */
9345                if (curr_stream->cont_capt) {
9346                        capture_pipe = find_pipe(pipes, num_pipes,
9347                                                 IA_CSS_PIPE_MODE_CAPTURE,
9348                                                 false);
9349                        if (!capture_pipe) {
9350                                err = -EINVAL;
9351                                goto ERR;
9352                        }
9353                }
9354                /* We do not support preview and video pipe at the same time */
9355                if (preview_pipe && video_pipe) {
9356                        err = -EINVAL;
9357                        goto ERR;
9358                }
9359
9360                if (preview_pipe && !preview_pipe->pipe_settings.preview.copy_pipe) {
9361                        err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, &copy_pipe, true);
9362                        if (err)
9363                                goto ERR;
9364                        ia_css_pipe_config_defaults(&copy_pipe->config);
9365                        preview_pipe->pipe_settings.preview.copy_pipe = copy_pipe;
9366                        copy_pipe->stream = curr_stream;
9367                }
9368                if (preview_pipe && curr_stream->cont_capt)
9369                        preview_pipe->pipe_settings.preview.capture_pipe = capture_pipe;
9370
9371                if (video_pipe && !video_pipe->pipe_settings.video.copy_pipe) {
9372                        err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, &copy_pipe, true);
9373                        if (err)
9374                                goto ERR;
9375                        ia_css_pipe_config_defaults(&copy_pipe->config);
9376                        video_pipe->pipe_settings.video.copy_pipe = copy_pipe;
9377                        copy_pipe->stream = curr_stream;
9378                }
9379                if (video_pipe && curr_stream->cont_capt)
9380                        video_pipe->pipe_settings.video.capture_pipe = capture_pipe;
9381
9382                if (preview_pipe && acc_pipe)
9383                        preview_pipe->pipe_settings.preview.acc_pipe = acc_pipe;
9384        }
9385        for (i = 0; i < num_pipes; i++) {
9386                curr_pipe = pipes[i];
9387                /* set current stream */
9388                curr_pipe->stream = curr_stream;
9389
9390                if (!IS_ISP2401) {
9391                        /* take over effective info */
9392
9393                        effective_res = curr_pipe->config.input_effective_res;
9394                        err = ia_css_util_check_res(
9395                                effective_res.width,
9396                                effective_res.height);
9397                        if (err)
9398                                goto ERR;
9399                }
9400                /* sensor binning per pipe */
9401                if (sensor_binning_changed)
9402                        sh_css_pipe_free_shading_table(curr_pipe);
9403        }
9404
9405        /* now pipes have been configured, info should be available */
9406        for (i = 0; i < num_pipes; i++) {
9407                struct ia_css_pipe_info *pipe_info = NULL;
9408
9409                curr_pipe = pipes[i];
9410
9411                err = sh_css_pipe_load_binaries(curr_pipe);
9412                if (err)
9413                        goto ERR;
9414
9415                /* handle each pipe */
9416                pipe_info = &curr_pipe->info;
9417                for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) {
9418                        err = sh_css_pipe_get_output_frame_info(curr_pipe,
9419                                                                &pipe_info->output_info[j], j);
9420                        if (err)
9421                                goto ERR;
9422                }
9423
9424                if (IS_ISP2401)
9425                        pipe_info->output_system_in_res_info = curr_pipe->config.output_system_in_res;
9426
9427                if (!spcopyonly) {
9428                        if (!IS_ISP2401)
9429                                err = sh_css_pipe_get_shading_info(curr_pipe,
9430                                                                   &pipe_info->shading_info,
9431                                                                   NULL);
9432                        else
9433                                err = sh_css_pipe_get_shading_info(curr_pipe,
9434                                                                   &pipe_info->shading_info,
9435                                                                   &curr_pipe->config);
9436
9437                        if (err)
9438                                goto ERR;
9439                        err = sh_css_pipe_get_grid_info(curr_pipe,
9440                                                        &pipe_info->grid_info);
9441                        if (err)
9442                                goto ERR;
9443                        for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) {
9444                                sh_css_pipe_get_viewfinder_frame_info(curr_pipe,
9445                                                                      &pipe_info->vf_output_info[j],
9446                                                                      j);
9447                                if (err)
9448                                        goto ERR;
9449                        }
9450                }
9451
9452                my_css.active_pipes[ia_css_pipe_get_pipe_num(curr_pipe)] = curr_pipe;
9453        }
9454
9455        curr_stream->started = false;
9456
9457        /* Map SP threads before doing anything. */
9458        err = map_sp_threads(curr_stream, true);
9459        if (err) {
9460                IA_CSS_LOG("map_sp_threads: return_err=%d", err);
9461                goto ERR;
9462        }
9463
9464        for (i = 0; i < num_pipes; i++) {
9465                curr_pipe = pipes[i];
9466                ia_css_pipe_map_queue(curr_pipe, true);
9467        }
9468
9469        /* Create host side pipeline objects without stages */
9470        err = create_host_pipeline_structure(curr_stream);
9471        if (err) {
9472                IA_CSS_LOG("create_host_pipeline_structure: return_err=%d", err);
9473                goto ERR;
9474        }
9475
9476        /* assign curr_stream */
9477        *stream = curr_stream;
9478
9479ERR:
9480        if (!err) {
9481                /* working mode: enter into the seed list */
9482                if (my_css_save.mode == sh_css_mode_working) {
9483                        for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
9484                                if (!my_css_save.stream_seeds[i].stream) {
9485                                        IA_CSS_LOG("entered stream into loc=%d", i);
9486                                        my_css_save.stream_seeds[i].orig_stream = stream;
9487                                        my_css_save.stream_seeds[i].stream = curr_stream;
9488                                        my_css_save.stream_seeds[i].num_pipes = num_pipes;
9489                                        my_css_save.stream_seeds[i].stream_config = *stream_config;
9490                                        for (j = 0; j < num_pipes; j++) {
9491                                                my_css_save.stream_seeds[i].pipe_config[j] = pipes[j]->config;
9492                                                my_css_save.stream_seeds[i].pipes[j] = pipes[j];
9493                                                my_css_save.stream_seeds[i].orig_pipes[j] = &pipes[j];
9494                                        }
9495                                        break;
9496                                }
9497                        }
9498                } else {
9499                        ia_css_stream_destroy(curr_stream);
9500                }
9501        } else {
9502                ia_css_stream_destroy(curr_stream);
9503        }
9504        IA_CSS_LEAVE("return_err=%d mode=%d", err, my_css_save.mode);
9505        return err;
9506}
9507
9508int
9509ia_css_stream_destroy(struct ia_css_stream *stream)
9510{
9511        int i;
9512        int err = 0;
9513
9514        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
9515        if (!stream) {
9516                err = -EINVAL;
9517                IA_CSS_LEAVE_ERR_PRIVATE(err);
9518                return err;
9519        }
9520
9521        ia_css_stream_isp_parameters_uninit(stream);
9522
9523        if ((stream->last_pipe) &&
9524            ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) {
9525#if defined(ISP2401)
9526                bool free_mpi;
9527
9528                for (i = 0; i < stream->num_pipes; i++) {
9529                        struct ia_css_pipe *entry = stream->pipes[i];
9530                        unsigned int sp_thread_id;
9531                        struct sh_css_sp_pipeline_terminal *sp_pipeline_input_terminal;
9532
9533                        assert(entry);
9534                        if (entry) {
9535                                /* get the SP thread id */
9536                                if (!ia_css_pipeline_get_sp_thread_id(
9537                                        ia_css_pipe_get_pipe_num(entry), &sp_thread_id))
9538                                        return -EINVAL;
9539                                /* get the target input terminal */
9540                                sp_pipeline_input_terminal =
9541                                &sh_css_sp_group.pipe_io[sp_thread_id].input;
9542
9543                                for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) {
9544                                        ia_css_isys_stream_h isys_stream =
9545                                        &sp_pipeline_input_terminal->context.virtual_input_system_stream[i];
9546                                        if (stream->config.isys_config[i].valid && isys_stream->valid)
9547                                                ia_css_isys_stream_destroy(isys_stream);
9548                                }
9549                        }
9550                }
9551                free_mpi = stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
9552                if (IS_ISP2401) {
9553                        free_mpi |= stream->config.mode == IA_CSS_INPUT_MODE_TPG;
9554                        free_mpi |= stream->config.mode == IA_CSS_INPUT_MODE_PRBS;
9555                }
9556
9557                if (free_mpi) {
9558                        for (i = 0; i < stream->num_pipes; i++) {
9559                                struct ia_css_pipe *entry = stream->pipes[i];
9560                                /* free any mipi frames that are remaining:
9561                                    * some test stream create-destroy cycles do not generate output frames
9562                                    * and the mipi buffer is not freed in the deque function
9563                                    */
9564                                if (entry)
9565                                        free_mipi_frames(entry);
9566                        }
9567                }
9568                stream_unregister_with_csi_rx(stream);
9569#endif
9570
9571                for (i = 0; i < stream->num_pipes; i++) {
9572                        struct ia_css_pipe *curr_pipe = stream->pipes[i];
9573
9574                        assert(curr_pipe);
9575                        ia_css_pipe_map_queue(curr_pipe, false);
9576                }
9577
9578                err = map_sp_threads(stream, false);
9579                if (err) {
9580                        IA_CSS_LEAVE_ERR_PRIVATE(err);
9581                        return err;
9582                }
9583        }
9584
9585        /* remove references from pipes to stream */
9586        for (i = 0; i < stream->num_pipes; i++) {
9587                struct ia_css_pipe *entry = stream->pipes[i];
9588
9589                assert(entry);
9590                if (entry) {
9591                        /* clear reference to stream */
9592                        entry->stream = NULL;
9593                        /* check internal copy pipe */
9594                        if (entry->mode == IA_CSS_PIPE_ID_PREVIEW &&
9595                            entry->pipe_settings.preview.copy_pipe) {
9596                                IA_CSS_LOG("clearing stream on internal preview copy pipe");
9597                                entry->pipe_settings.preview.copy_pipe->stream = NULL;
9598                        }
9599                        if (entry->mode == IA_CSS_PIPE_ID_VIDEO &&
9600                            entry->pipe_settings.video.copy_pipe) {
9601                                IA_CSS_LOG("clearing stream on internal video copy pipe");
9602                                entry->pipe_settings.video.copy_pipe->stream = NULL;
9603                        }
9604                        err = sh_css_pipe_unload_binaries(entry);
9605                }
9606        }
9607        /* free associated memory of stream struct */
9608        kfree(stream->pipes);
9609        stream->pipes = NULL;
9610        stream->num_pipes = 0;
9611
9612        /* working mode: take out of the seed list */
9613        if (my_css_save.mode == sh_css_mode_working) {
9614                for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
9615                        if (my_css_save.stream_seeds[i].stream == stream) {
9616                                IA_CSS_LOG("took out stream %d", i);
9617                                my_css_save.stream_seeds[i].stream = NULL;
9618                                break;
9619                        }
9620                }
9621        }
9622
9623        kfree(stream);
9624        IA_CSS_LEAVE_ERR(err);
9625
9626        return err;
9627}
9628
9629int
9630ia_css_stream_get_info(const struct ia_css_stream *stream,
9631                       struct ia_css_stream_info *stream_info)
9632{
9633        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_info: enter/exit\n");
9634        assert(stream);
9635        assert(stream_info);
9636
9637        *stream_info = stream->info;
9638        return 0;
9639}
9640
9641/*
9642    * Rebuild a stream, including allocating structs, setting configuration and
9643    * building the required pipes.
9644    * The data is taken from the css_save struct updated upon stream creation.
9645    * The stream handle is used to identify the correct entry in the css_save struct
9646    */
9647int
9648ia_css_stream_load(struct ia_css_stream *stream)
9649{
9650        int i, j, err;
9651
9652        if (IS_ISP2401) {
9653                /* TODO remove function - DEPRECATED */
9654                (void)stream;
9655                return -ENOTSUPP;
9656        }
9657
9658        assert(stream);
9659        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() enter,\n");
9660        for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
9661                if (my_css_save.stream_seeds[i].stream != stream)
9662                        continue;
9663
9664                for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) {
9665                        int k;
9666
9667                        err = ia_css_pipe_create(&my_css_save.stream_seeds[i].pipe_config[j],
9668                                                 &my_css_save.stream_seeds[i].pipes[j]);
9669                        if (!err)
9670                                continue;
9671
9672                        for (k = 0; k < j; k++)
9673                                ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[k]);
9674                        return err;
9675                }
9676                err = ia_css_stream_create(&my_css_save.stream_seeds[i].stream_config,
9677                                           my_css_save.stream_seeds[i].num_pipes,
9678                                           my_css_save.stream_seeds[i].pipes,
9679                                           &my_css_save.stream_seeds[i].stream);
9680                if (!err)
9681                        break;
9682
9683                ia_css_stream_destroy(stream);
9684                for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
9685                        ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
9686                return err;
9687        }
9688
9689        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() exit,\n");
9690        return 0;
9691}
9692
9693int
9694ia_css_stream_start(struct ia_css_stream *stream)
9695{
9696        int err = 0;
9697
9698        IA_CSS_ENTER("stream = %p", stream);
9699        if ((!stream) || (!stream->last_pipe)) {
9700                IA_CSS_LEAVE_ERR(-EINVAL);
9701                return -EINVAL;
9702        }
9703        IA_CSS_LOG("starting %d", stream->last_pipe->mode);
9704
9705        sh_css_sp_set_disable_continuous_viewfinder(stream->disable_cont_vf);
9706
9707        /* Create host side pipeline. */
9708        err = create_host_pipeline(stream);
9709        if (err) {
9710                IA_CSS_LEAVE_ERR(err);
9711                return err;
9712        }
9713
9714#if defined(ISP2401)
9715        if ((stream->config.mode == IA_CSS_INPUT_MODE_SENSOR) ||
9716            (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR))
9717                stream_register_with_csi_rx(stream);
9718#endif
9719
9720#if !defined(ISP2401)
9721        /* Initialize mipi size checks */
9722        if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
9723                unsigned int idx;
9724                unsigned int port = (unsigned int)(stream->config.source.port.port);
9725
9726                for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) {
9727                        sh_css_sp_group.config.mipi_sizes_for_check[port][idx] =
9728                        sh_css_get_mipi_sizes_for_check(port, idx);
9729                }
9730        }
9731#endif
9732
9733        if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) {
9734                err = sh_css_config_input_network(stream);
9735                if (err)
9736                        return err;
9737        }
9738
9739        err = sh_css_pipe_start(stream);
9740        IA_CSS_LEAVE_ERR(err);
9741        return err;
9742}
9743
9744int
9745ia_css_stream_stop(struct ia_css_stream *stream)
9746{
9747        int err = 0;
9748
9749        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop() enter/exit\n");
9750        assert(stream);
9751        assert(stream->last_pipe);
9752        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop: stopping %d\n",
9753                            stream->last_pipe->mode);
9754
9755#if !defined(ISP2401)
9756        /* De-initialize mipi size checks */
9757        if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
9758                unsigned int idx;
9759                unsigned int port = (unsigned int)(stream->config.source.port.port);
9760
9761                for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++)
9762                        sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 0;
9763        }
9764#endif
9765
9766        if (!IS_ISP2401)
9767                err = ia_css_pipeline_request_stop(&stream->last_pipe->pipeline);
9768        else
9769                err = sh_css_pipes_stop(stream);
9770
9771        if (err)
9772                return err;
9773
9774        /* Ideally, unmapping should happen after pipeline_stop, but current
9775            * semantics do not allow that. */
9776        /* err = map_sp_threads(stream, false); */
9777
9778        return err;
9779}
9780
9781bool
9782ia_css_stream_has_stopped(struct ia_css_stream *stream)
9783{
9784        bool stopped;
9785
9786        assert(stream);
9787
9788        if (!IS_ISP2401)
9789                stopped = ia_css_pipeline_has_stopped(&stream->last_pipe->pipeline);
9790        else
9791                stopped = sh_css_pipes_have_stopped(stream);
9792
9793        return stopped;
9794}
9795
9796/* ISP2400 */
9797/*
9798    * Destroy the stream and all the pipes related to it.
9799    * The stream handle is used to identify the correct entry in the css_save struct
9800    */
9801int
9802ia_css_stream_unload(struct ia_css_stream *stream)
9803{
9804        int i;
9805
9806        assert(stream);
9807        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_unload() enter,\n");
9808        /* some checks */
9809        assert(stream);
9810        for (i = 0; i < MAX_ACTIVE_STREAMS; i++)
9811                if (my_css_save.stream_seeds[i].stream == stream) {
9812                        int j;
9813
9814                        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9815                                            "ia_css_stream_unload(): unloading %d (%p)\n", i,
9816                                            my_css_save.stream_seeds[i].stream);
9817                        ia_css_stream_destroy(stream);
9818                        for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
9819                                ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
9820                        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9821                                            "ia_css_stream_unload(): after unloading %d (%p)\n", i,
9822                                            my_css_save.stream_seeds[i].stream);
9823                        break;
9824                }
9825        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_unload() exit,\n");
9826        return 0;
9827}
9828
9829int
9830ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe,
9831                            enum ia_css_pipe_id *pipe_id)
9832{
9833        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_temp_pipe_to_pipe_id() enter/exit\n");
9834        if (pipe)
9835                *pipe_id = pipe->mode;
9836        else
9837                *pipe_id = IA_CSS_PIPE_ID_COPY;
9838
9839        return 0;
9840}
9841
9842enum atomisp_input_format
9843ia_css_stream_get_format(const struct ia_css_stream *stream)
9844{
9845        return stream->config.input_config.format;
9846}
9847
9848bool
9849ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream)
9850{
9851        return (stream->config.pixels_per_clock == 2);
9852}
9853
9854struct ia_css_binary *
9855ia_css_stream_get_shading_correction_binary(const struct ia_css_stream
9856        *stream)
9857{
9858        struct ia_css_pipe *pipe;
9859
9860        assert(stream);
9861
9862        pipe = stream->pipes[0];
9863
9864        if (stream->num_pipes == 2) {
9865                assert(stream->pipes[1]);
9866                if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO ||
9867                    stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
9868                        pipe = stream->pipes[1];
9869        }
9870
9871        return ia_css_pipe_get_shading_correction_binary(pipe);
9872}
9873
9874struct ia_css_binary *
9875ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream)
9876{
9877        int i;
9878        struct ia_css_pipe *video_pipe = NULL;
9879
9880        /* First we find the video pipe */
9881        for (i = 0; i < stream->num_pipes; i++) {
9882                struct ia_css_pipe *pipe = stream->pipes[i];
9883
9884                if (pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) {
9885                        video_pipe = pipe;
9886                        break;
9887                }
9888        }
9889        if (video_pipe)
9890                return &video_pipe->pipe_settings.video.video_binary;
9891        return NULL;
9892}
9893
9894struct ia_css_binary *
9895ia_css_stream_get_3a_binary(const struct ia_css_stream *stream)
9896{
9897        struct ia_css_pipe *pipe;
9898        struct ia_css_binary *s3a_binary = NULL;
9899
9900        assert(stream);
9901
9902        pipe = stream->pipes[0];
9903
9904        if (stream->num_pipes == 2) {
9905                assert(stream->pipes[1]);
9906                if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO ||
9907                    stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
9908                        pipe = stream->pipes[1];
9909        }
9910
9911        s3a_binary = ia_css_pipe_get_s3a_binary(pipe);
9912
9913        return s3a_binary;
9914}
9915
9916int
9917ia_css_stream_set_output_padded_width(struct ia_css_stream *stream,
9918                                      unsigned int output_padded_width)
9919{
9920        struct ia_css_pipe *pipe;
9921
9922        assert(stream);
9923
9924        pipe = stream->last_pipe;
9925
9926        assert(pipe);
9927
9928        /* set the config also just in case (redundant info? why do we save config in pipe?) */
9929        pipe->config.output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width;
9930        pipe->output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width;
9931
9932        return 0;
9933}
9934
9935static struct ia_css_binary *
9936ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe)
9937{
9938        struct ia_css_binary *binary = NULL;
9939
9940        assert(pipe);
9941
9942        switch (pipe->config.mode) {
9943        case IA_CSS_PIPE_MODE_PREVIEW:
9944                binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary;
9945                break;
9946        case IA_CSS_PIPE_MODE_VIDEO:
9947                binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
9948                break;
9949        case IA_CSS_PIPE_MODE_CAPTURE:
9950                if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
9951                        unsigned int i;
9952
9953                        for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
9954                                if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.sc) {
9955                                        binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i];
9956                                        break;
9957                                }
9958                        }
9959                } else if (pipe->config.default_capture_config.mode ==
9960                            IA_CSS_CAPTURE_MODE_BAYER)
9961                        binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
9962                else if (pipe->config.default_capture_config.mode ==
9963                            IA_CSS_CAPTURE_MODE_ADVANCED ||
9964                            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
9965                        if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1)
9966                                binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
9967                        else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2)
9968                                binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary;
9969                }
9970                break;
9971        default:
9972                break;
9973        }
9974
9975        if (binary && binary->info->sp.enable.sc)
9976                return binary;
9977
9978        return NULL;
9979}
9980
9981static struct ia_css_binary *
9982ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe)
9983{
9984        struct ia_css_binary *binary = NULL;
9985
9986        assert(pipe);
9987
9988        switch (pipe->config.mode) {
9989        case IA_CSS_PIPE_MODE_PREVIEW:
9990                binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary;
9991                break;
9992        case IA_CSS_PIPE_MODE_VIDEO:
9993                binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
9994                break;
9995        case IA_CSS_PIPE_MODE_CAPTURE:
9996                if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
9997                        unsigned int i;
9998
9999                        for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
10000                                if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) {
10001                                        binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i];
10002                                        break;
10003                                }
10004                        }
10005                } else if (pipe->config.default_capture_config.mode ==
10006                            IA_CSS_CAPTURE_MODE_BAYER) {
10007                        binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
10008                } else if (pipe->config.default_capture_config.mode ==
10009                            IA_CSS_CAPTURE_MODE_ADVANCED ||
10010                            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
10011                        if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1)
10012                                binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
10013                        else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2)
10014                                binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary;
10015                        else
10016                                assert(0);
10017                }
10018                break;
10019        default:
10020                break;
10021        }
10022
10023        if (binary && !binary->info->sp.enable.s3a)
10024                binary = NULL;
10025
10026        return binary;
10027}
10028
10029static struct ia_css_binary *
10030ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe)
10031{
10032        struct ia_css_binary *binary = NULL;
10033
10034        assert(pipe);
10035
10036        switch (pipe->config.mode) {
10037        case IA_CSS_PIPE_MODE_VIDEO:
10038                binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
10039                break;
10040        default:
10041                break;
10042        }
10043
10044        if (binary && !binary->info->sp.enable.dis)
10045                binary = NULL;
10046
10047        return binary;
10048}
10049
10050struct ia_css_pipeline *
10051ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe)
10052{
10053        assert(pipe);
10054
10055        return (struct ia_css_pipeline *)&pipe->pipeline;
10056}
10057
10058unsigned int
10059ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe)
10060{
10061        assert(pipe);
10062
10063        /* KW was not sure this function was not returning a value
10064            that was out of range; so added an assert, and, for the
10065            case when asserts are not enabled, clip to the largest
10066            value; pipe_num is unsigned so the value cannot be too small
10067        */
10068        assert(pipe->pipe_num < IA_CSS_PIPELINE_NUM_MAX);
10069
10070        if (pipe->pipe_num >= IA_CSS_PIPELINE_NUM_MAX)
10071                return (IA_CSS_PIPELINE_NUM_MAX - 1);
10072
10073        return pipe->pipe_num;
10074}
10075
10076unsigned int
10077ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe)
10078{
10079        assert(pipe);
10080
10081        return (unsigned int)pipe->config.isp_pipe_version;
10082}
10083
10084#define SP_START_TIMEOUT_US 30000000
10085
10086int
10087ia_css_start_sp(void)
10088{
10089        unsigned long timeout;
10090        int err = 0;
10091
10092        IA_CSS_ENTER("");
10093        sh_css_sp_start_isp();
10094
10095        /* waiting for the SP is completely started */
10096        timeout = SP_START_TIMEOUT_US;
10097        while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout) {
10098                timeout--;
10099                udelay(1);
10100        }
10101        if (timeout == 0) {
10102                IA_CSS_ERROR("timeout during SP initialization");
10103                return -EINVAL;
10104        }
10105
10106        /* Workaround, in order to run two streams in parallel. See TASK 4271*/
10107        /* TODO: Fix this. */
10108
10109        sh_css_init_host_sp_control_vars();
10110
10111        /* buffers should be initialized only when sp is started */
10112        /* AM: At the moment it will be done only when there is no stream active. */
10113
10114        sh_css_setup_queues();
10115        ia_css_bufq_dump_queue_info();
10116
10117        IA_CSS_LEAVE_ERR(err);
10118        return err;
10119}
10120
10121/*
10122    *   Time to wait SP for termincate. Only condition when this can happen
10123    *   is a fatal hw failure, but we must be able to detect this and emit
10124    *   a proper error trace.
10125    */
10126#define SP_SHUTDOWN_TIMEOUT_US 200000
10127
10128int
10129ia_css_stop_sp(void)
10130{
10131        unsigned long timeout;
10132        int err = 0;
10133
10134        IA_CSS_ENTER("void");
10135
10136        if (!sh_css_sp_is_running()) {
10137                err = -EINVAL;
10138                IA_CSS_LEAVE("SP already stopped : return_err=%d", err);
10139
10140                /* Return an error - stop SP should not have been called by driver */
10141                return err;
10142        }
10143
10144        /* For now, stop whole SP */
10145        if (!IS_ISP2401) {
10146                sh_css_write_host2sp_command(host2sp_cmd_terminate);
10147        } else {
10148                if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) {
10149                        IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed");
10150                        ia_css_debug_dump_sp_sw_debug_info();
10151                        ia_css_debug_dump_debug_info(NULL);
10152                }
10153        }
10154
10155        sh_css_sp_set_sp_running(false);
10156
10157        timeout = SP_SHUTDOWN_TIMEOUT_US;
10158        while (!ia_css_spctrl_is_idle(SP0_ID) && timeout) {
10159                timeout--;
10160                udelay(1);
10161        }
10162        if (ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED)
10163                IA_CSS_WARNING("SP has not terminated (SW)");
10164
10165        if (timeout == 0) {
10166                IA_CSS_WARNING("SP is not idle");
10167                ia_css_debug_dump_sp_sw_debug_info();
10168        }
10169        timeout = SP_SHUTDOWN_TIMEOUT_US;
10170        while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout) {
10171                timeout--;
10172                udelay(1);
10173        }
10174        if (timeout == 0) {
10175                IA_CSS_WARNING("ISP is not idle");
10176                ia_css_debug_dump_sp_sw_debug_info();
10177        }
10178
10179        sh_css_hmm_buffer_record_uninit();
10180
10181        /* clear pending param sets from refcount */
10182        sh_css_param_clear_param_sets();
10183
10184        IA_CSS_LEAVE_ERR(err);
10185        return err;
10186}
10187
10188int
10189ia_css_update_continuous_frames(struct ia_css_stream *stream)
10190{
10191        struct ia_css_pipe *pipe;
10192        unsigned int i;
10193
10194        ia_css_debug_dtrace(
10195            IA_CSS_DEBUG_TRACE,
10196            "sh_css_update_continuous_frames() enter:\n");
10197
10198        if (!stream) {
10199                ia_css_debug_dtrace(
10200                    IA_CSS_DEBUG_TRACE,
10201                    "sh_css_update_continuous_frames() leave: invalid stream, return_void\n");
10202                return -EINVAL;
10203        }
10204
10205        pipe = stream->continuous_pipe;
10206
10207        for (i = stream->config.init_num_cont_raw_buf;
10208                i < stream->config.target_num_cont_raw_buf; i++)
10209                sh_css_update_host2sp_offline_frame(i,
10210                                                    pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
10211
10212        sh_css_update_host2sp_cont_num_raw_frames
10213        (stream->config.target_num_cont_raw_buf, true);
10214        ia_css_debug_dtrace(
10215            IA_CSS_DEBUG_TRACE,
10216            "sh_css_update_continuous_frames() leave: return_void\n");
10217
10218        return 0;
10219}
10220
10221void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map)
10222{
10223        unsigned int thread_id;
10224        unsigned int pipe_num;
10225        bool need_input_queue;
10226
10227        IA_CSS_ENTER("");
10228        assert(pipe);
10229
10230        pipe_num = pipe->pipe_num;
10231
10232        ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
10233
10234#if defined(ISP2401)
10235        need_input_queue = true;
10236#else
10237        need_input_queue = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
10238#endif
10239
10240        /* map required buffer queues to resources */
10241        /* TODO: to be improved */
10242        if (pipe->mode == IA_CSS_PIPE_ID_PREVIEW) {
10243                if (need_input_queue)
10244                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10245                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10246                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10247                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10248#if defined SH_CSS_ENABLE_METADATA
10249                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10250#endif
10251                if (pipe->pipe_settings.preview.preview_binary.info &&
10252                    pipe->pipe_settings.preview.preview_binary.info->sp.enable.s3a)
10253                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10254        } else if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE) {
10255                unsigned int i;
10256
10257                if (need_input_queue)
10258                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10259                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10260                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map);
10261                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10262                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10263#if defined SH_CSS_ENABLE_METADATA
10264                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10265#endif
10266                if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
10267                        for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
10268                                if (pipe->pipe_settings.capture.primary_binary[i].info &&
10269                                    pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) {
10270                                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10271                                        break;
10272                                }
10273                        }
10274                } else if (pipe->config.default_capture_config.mode ==
10275                            IA_CSS_CAPTURE_MODE_ADVANCED ||
10276                            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT ||
10277                            pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) {
10278                        if (pipe->pipe_settings.capture.pre_isp_binary.info &&
10279                            pipe->pipe_settings.capture.pre_isp_binary.info->sp.enable.s3a)
10280                                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10281                }
10282        } else if (pipe->mode == IA_CSS_PIPE_ID_VIDEO) {
10283                if (need_input_queue)
10284                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10285                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10286                if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0])
10287                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map);
10288                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10289                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10290#if defined SH_CSS_ENABLE_METADATA
10291                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10292#endif
10293                if (pipe->pipe_settings.video.video_binary.info &&
10294                    pipe->pipe_settings.video.video_binary.info->sp.enable.s3a)
10295                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10296                if (pipe->pipe_settings.video.video_binary.info &&
10297                    (pipe->pipe_settings.video.video_binary.info->sp.enable.dis
10298                    ))
10299                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_DIS_STATISTICS, map);
10300        } else if (pipe->mode == IA_CSS_PIPE_ID_COPY) {
10301                if (need_input_queue)
10302                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10303                if (!pipe->stream->config.continuous)
10304                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10305#if defined SH_CSS_ENABLE_METADATA
10306                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10307#endif
10308        } else if (pipe->mode == IA_CSS_PIPE_ID_ACC) {
10309                if (need_input_queue)
10310                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10311                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10312                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10313                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10314#if defined SH_CSS_ENABLE_METADATA
10315                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10316#endif
10317        } else if (pipe->mode == IA_CSS_PIPE_ID_YUVPP) {
10318                unsigned int idx;
10319
10320                for (idx = 0; idx < IA_CSS_PIPE_MAX_OUTPUT_STAGE; idx++) {
10321                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, map);
10322                        if (pipe->enable_viewfinder[idx])
10323                                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, map);
10324                }
10325                if (need_input_queue)
10326                        ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10327                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10328#if defined SH_CSS_ENABLE_METADATA
10329                ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10330#endif
10331        }
10332        IA_CSS_LEAVE("");
10333}
10334
10335#if CONFIG_ON_FRAME_ENQUEUE()
10336static int set_config_on_frame_enqueue(struct ia_css_frame_info
10337        *info, struct frame_data_wrapper *frame)
10338{
10339        frame->config_on_frame_enqueue.padded_width = 0;
10340
10341        /* currently we support configuration on frame enqueue only on YUV formats */
10342        /* on other formats the padded_width is zeroed for no configuration override */
10343        switch (info->format) {
10344        case IA_CSS_FRAME_FORMAT_YUV420:
10345        case IA_CSS_FRAME_FORMAT_NV12:
10346                if (info->padded_width > info->res.width)
10347                        frame->config_on_frame_enqueue.padded_width = info->padded_width;
10348                else if ((info->padded_width < info->res.width) && (info->padded_width > 0))
10349                        return -EINVAL;
10350
10351                /* nothing to do if width == padded width or padded width is zeroed (the same) */
10352                break;
10353        default:
10354                break;
10355        }
10356
10357        return 0;
10358}
10359#endif
10360
10361int
10362ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id)
10363{
10364        int ret;
10365
10366        IA_CSS_ENTER("");
10367
10368        /* Only continuous streams have a tagger to which we can send the
10369            * unlock message. */
10370        if (!stream || !stream->config.continuous) {
10371                IA_CSS_ERROR("invalid stream pointer");
10372                return -EINVAL;
10373        }
10374
10375        if (exp_id > IA_CSS_ISYS_MAX_EXPOSURE_ID ||
10376            exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID) {
10377                IA_CSS_ERROR("invalid exposure ID: %d\n", exp_id);
10378                return -EINVAL;
10379        }
10380
10381        /* Send the event. Since we verified that the exp_id is valid,
10382            * we can safely assign it to an 8-bit argument here. */
10383        ret = ia_css_bufq_enqueue_psys_event(
10384            IA_CSS_PSYS_SW_EVENT_UNLOCK_RAW_BUFFER, exp_id, 0, 0);
10385
10386        IA_CSS_LEAVE_ERR(ret);
10387        return ret;
10388}
10389
10390/* @brief       Set the state (Enable or Disable) of the Extension stage in the
10391    *           given pipe.
10392    */
10393int
10394ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
10395                              bool enable)
10396{
10397        unsigned int thread_id;
10398        struct ia_css_pipeline_stage *stage;
10399        int err = 0;
10400
10401        IA_CSS_ENTER("");
10402
10403        /* Parameter Check */
10404        if (!pipe || !pipe->stream) {
10405                IA_CSS_ERROR("Invalid Pipe.");
10406                err = -EINVAL;
10407        } else if (!(pipe->config.acc_extension)) {
10408                IA_CSS_ERROR("Invalid Pipe(No Extension Firmware)");
10409                err = -EINVAL;
10410        } else if (!sh_css_sp_is_running()) {
10411                IA_CSS_ERROR("Leaving: queue unavailable.");
10412                err = -EBUSY;
10413        } else {
10414                /* Query the threadid and stage_num for the Extension firmware*/
10415                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
10416                err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
10417                if (!err) {
10418                        /* Set the Extension State;. TODO: Add check for stage firmware.type (QOS)*/
10419                        err = ia_css_bufq_enqueue_psys_event(
10420                            (uint8_t)IA_CSS_PSYS_SW_EVENT_STAGE_ENABLE_DISABLE,
10421                            (uint8_t)thread_id,
10422                            (uint8_t)stage->stage_num,
10423                            enable ? 1 : 0);
10424                        if (!err) {
10425                                if (enable)
10426                                        SH_CSS_QOS_STAGE_ENABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num);
10427                                else
10428                                        SH_CSS_QOS_STAGE_DISABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num);
10429                        }
10430                }
10431        }
10432        IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, enable);
10433        return err;
10434}
10435
10436/*      @brief  Get the state (Enable or Disable) of the Extension stage in the
10437    *   given pipe.
10438    */
10439int
10440ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
10441                              bool *enable)
10442{
10443        struct ia_css_pipeline_stage *stage;
10444        unsigned int thread_id;
10445        int err = 0;
10446
10447        IA_CSS_ENTER("");
10448
10449        /* Parameter Check */
10450        if (!pipe || !pipe->stream) {
10451                IA_CSS_ERROR("Invalid Pipe.");
10452                err = -EINVAL;
10453        } else if (!(pipe->config.acc_extension)) {
10454                IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
10455                err = -EINVAL;
10456        } else if (!sh_css_sp_is_running()) {
10457                IA_CSS_ERROR("Leaving: queue unavailable.");
10458                err = -EBUSY;
10459        } else {
10460                /* Query the threadid and stage_num corresponding to the Extension firmware*/
10461                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
10462                err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
10463
10464                if (!err) {
10465                        /* Get the Extension State */
10466                        *enable = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id],
10467                                                                stage->stage_num)) ? true : false;
10468                }
10469        }
10470        IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, *enable);
10471        return err;
10472}
10473
10474/* ISP2401 */
10475int
10476ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
10477                                      u32 fw_handle,
10478                                      struct ia_css_isp_param_css_segments *css_seg,
10479                                      struct ia_css_isp_param_isp_segments *isp_seg)
10480{
10481        unsigned int HIVE_ADDR_sp_group;
10482        static struct sh_css_sp_group sp_group;
10483        static struct sh_css_sp_stage sp_stage;
10484        static struct sh_css_isp_stage isp_stage;
10485        const struct ia_css_fw_info *fw;
10486        unsigned int thread_id;
10487        struct ia_css_pipeline_stage *stage;
10488        int err = 0;
10489        int stage_num = 0;
10490        enum ia_css_isp_memories mem;
10491        bool enabled;
10492
10493        IA_CSS_ENTER("");
10494
10495        fw = &sh_css_sp_fw;
10496
10497        /* Parameter Check */
10498        if (!pipe || !pipe->stream) {
10499                IA_CSS_ERROR("Invalid Pipe.");
10500                err = -EINVAL;
10501        } else if (!(pipe->config.acc_extension)) {
10502                IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
10503                err = -EINVAL;
10504        } else if (!sh_css_sp_is_running()) {
10505                IA_CSS_ERROR("Leaving: queue unavailable.");
10506                err = -EBUSY;
10507        } else {
10508                /* Query the thread_id and stage_num corresponding to the Extension firmware */
10509                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
10510                err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
10511                if (!err) {
10512                        /* Get the Extension State */
10513                        enabled = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id],
10514                                                               stage->stage_num)) ? true : false;
10515                        /* Update mapped arg only when extension stage is not enabled */
10516                        if (enabled) {
10517                                IA_CSS_ERROR("Leaving: cannot update when stage is enabled.");
10518                                err = -EBUSY;
10519                        } else {
10520                                stage_num = stage->stage_num;
10521
10522                                HIVE_ADDR_sp_group = fw->info.sp.group;
10523                                sp_dmem_load(SP0_ID,
10524                                             (unsigned int)sp_address_of(sp_group),
10525                                             &sp_group,
10526                                             sizeof(struct sh_css_sp_group));
10527                                hmm_load(sp_group.pipe[thread_id].sp_stage_addr[stage_num],
10528                                         &sp_stage, sizeof(struct sh_css_sp_stage));
10529
10530                                hmm_load(sp_stage.isp_stage_addr,
10531                                         &isp_stage, sizeof(struct sh_css_isp_stage));
10532
10533                                for (mem = 0; mem < N_IA_CSS_ISP_MEMORIES; mem++) {
10534                                        isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address =
10535                                            css_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].address;
10536                                        isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].size =
10537                                            css_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].size;
10538                                        isp_stage.binary_info.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address
10539                                            =
10540                                                isp_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].address;
10541                                        isp_stage.binary_info.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].size
10542                                            =
10543                                                isp_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].size;
10544                                }
10545
10546                                hmm_store(sp_stage.isp_stage_addr,
10547                                          &isp_stage,
10548                                          sizeof(struct sh_css_isp_stage));
10549                        }
10550                }
10551        }
10552        IA_CSS_LEAVE("err:%d handle:%u", err, fw_handle);
10553        return err;
10554}
10555
10556#ifdef ISP2401
10557static int
10558aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
10559                       struct ia_css_pipe *pipes[],
10560                       bool *do_crop_status)
10561{
10562        int err = 0;
10563        int i;
10564        struct ia_css_pipe *curr_pipe;
10565        u32 pipe_mask = 0;
10566
10567        if ((!curr_stream) ||
10568            (curr_stream->num_pipes == 0) ||
10569            (!pipes) ||
10570            (!do_crop_status)) {
10571                err = -EINVAL;
10572                IA_CSS_LEAVE_ERR(err);
10573                return err;
10574        }
10575
10576        for (i = 0; i < curr_stream->num_pipes; i++) {
10577                curr_pipe = pipes[i];
10578                pipe_mask |= (1 << curr_pipe->config.mode);
10579        }
10580
10581        *do_crop_status =
10582        (((pipe_mask & (1 << IA_CSS_PIPE_MODE_PREVIEW)) ||
10583            (pipe_mask & (1 << IA_CSS_PIPE_MODE_VIDEO))) &&
10584            (pipe_mask & (1 << IA_CSS_PIPE_MODE_CAPTURE)) &&
10585            curr_stream->config.continuous);
10586        return 0;
10587}
10588
10589static bool
10590aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe)
10591{
10592        bool status = false;
10593
10594        if ((curr_pipe) && enabled) {
10595                if ((curr_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) ||
10596                    (curr_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) ||
10597                    (curr_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE))
10598                        status = true;
10599        }
10600
10601        return status;
10602}
10603
10604static int
10605aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
10606                  struct ia_css_resolution *effective_res)
10607{
10608        int err = 0;
10609        struct ia_css_resolution crop_res;
10610        struct ia_css_resolution *in_res = NULL;
10611        struct ia_css_resolution *out_res = NULL;
10612        bool use_bds_output_info = false;
10613        bool use_vf_pp_in_res = false;
10614        bool use_capt_pp_in_res = false;
10615
10616        if ((!curr_pipe) ||
10617            (!effective_res)) {
10618                err = -EINVAL;
10619                IA_CSS_LEAVE_ERR(err);
10620                return err;
10621        }
10622
10623        if ((curr_pipe->config.mode != IA_CSS_PIPE_MODE_PREVIEW) &&
10624            (curr_pipe->config.mode != IA_CSS_PIPE_MODE_VIDEO) &&
10625            (curr_pipe->config.mode != IA_CSS_PIPE_MODE_CAPTURE)) {
10626                err = -EINVAL;
10627                IA_CSS_LEAVE_ERR(err);
10628                return err;
10629        }
10630
10631        use_bds_output_info =
10632        ((curr_pipe->bds_output_info.res.width != 0) &&
10633            (curr_pipe->bds_output_info.res.height != 0));
10634
10635        use_vf_pp_in_res =
10636        ((curr_pipe->config.vf_pp_in_res.width != 0) &&
10637            (curr_pipe->config.vf_pp_in_res.height != 0));
10638
10639        use_capt_pp_in_res =
10640        ((curr_pipe->config.capt_pp_in_res.width != 0) &&
10641            (curr_pipe->config.capt_pp_in_res.height != 0));
10642
10643        in_res = &curr_pipe->stream->config.input_config.effective_res;
10644        out_res = &curr_pipe->output_info[0].res;
10645
10646        switch (curr_pipe->config.mode) {
10647        case IA_CSS_PIPE_MODE_PREVIEW:
10648                if (use_bds_output_info)
10649                        out_res = &curr_pipe->bds_output_info.res;
10650                else if (use_vf_pp_in_res)
10651                        out_res = &curr_pipe->config.vf_pp_in_res;
10652                break;
10653        case IA_CSS_PIPE_MODE_VIDEO:
10654                if (use_bds_output_info)
10655                        out_res = &curr_pipe->bds_output_info.res;
10656                break;
10657        case IA_CSS_PIPE_MODE_CAPTURE:
10658                if (use_capt_pp_in_res)
10659                        out_res = &curr_pipe->config.capt_pp_in_res;
10660                break;
10661        case IA_CSS_PIPE_MODE_ACC:
10662        case IA_CSS_PIPE_MODE_COPY:
10663        case IA_CSS_PIPE_MODE_YUVPP:
10664        default:
10665                IA_CSS_ERROR("aspect ratio cropping invalid args: mode[%d]\n",
10666                             curr_pipe->config.mode);
10667                assert(0);
10668                break;
10669        }
10670
10671        err = ia_css_frame_find_crop_resolution(in_res, out_res, &crop_res);
10672        if (!err)
10673                *effective_res = crop_res;
10674        else
10675                /* in case of error fallback to default
10676                    * effective resolution from driver. */
10677                IA_CSS_LOG("ia_css_frame_find_crop_resolution() failed with err(%d)", err);
10678
10679        return err;
10680}
10681#endif
10682
10683static void
10684sh_css_hmm_buffer_record_init(void)
10685{
10686        int i;
10687
10688        for (i = 0; i < MAX_HMM_BUFFER_NUM; i++)
10689                sh_css_hmm_buffer_record_reset(&hmm_buffer_record[i]);
10690}
10691
10692static void
10693sh_css_hmm_buffer_record_uninit(void)
10694{
10695        int i;
10696        struct sh_css_hmm_buffer_record *buffer_record = NULL;
10697
10698        buffer_record = &hmm_buffer_record[0];
10699        for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
10700                if (buffer_record->in_use) {
10701                        if (buffer_record->h_vbuf)
10702                                ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &buffer_record->h_vbuf);
10703                        sh_css_hmm_buffer_record_reset(buffer_record);
10704                }
10705                buffer_record++;
10706        }
10707}
10708
10709static void
10710sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record)
10711{
10712        assert(buffer_record);
10713        buffer_record->in_use = false;
10714        buffer_record->type = IA_CSS_BUFFER_TYPE_INVALID;
10715        buffer_record->h_vbuf = NULL;
10716        buffer_record->kernel_ptr = 0;
10717}
10718
10719static struct sh_css_hmm_buffer_record
10720*sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf,
10721                                    enum ia_css_buffer_type type,
10722                                    hrt_address kernel_ptr)
10723{
10724        int i;
10725        struct sh_css_hmm_buffer_record *buffer_record = NULL;
10726        struct sh_css_hmm_buffer_record *out_buffer_record = NULL;
10727
10728        assert(h_vbuf);
10729        assert((type > IA_CSS_BUFFER_TYPE_INVALID) &&
10730               (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE));
10731        assert(kernel_ptr != 0);
10732
10733        buffer_record = &hmm_buffer_record[0];
10734        for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
10735                if (!buffer_record->in_use) {
10736                        buffer_record->in_use = true;
10737                        buffer_record->type = type;
10738                        buffer_record->h_vbuf = h_vbuf;
10739                        buffer_record->kernel_ptr = kernel_ptr;
10740                        out_buffer_record = buffer_record;
10741                        break;
10742                }
10743                buffer_record++;
10744        }
10745
10746        return out_buffer_record;
10747}
10748
10749static struct sh_css_hmm_buffer_record
10750*sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr,
10751                                    enum ia_css_buffer_type type)
10752{
10753        int i;
10754        struct sh_css_hmm_buffer_record *buffer_record = NULL;
10755        bool found_record = false;
10756
10757        buffer_record = &hmm_buffer_record[0];
10758        for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
10759                if ((buffer_record->in_use) &&
10760                    (buffer_record->type == type) &&
10761                    (buffer_record->h_vbuf) &&
10762                    (buffer_record->h_vbuf->vptr == ddr_buffer_addr)) {
10763                        found_record = true;
10764                        break;
10765                }
10766                buffer_record++;
10767        }
10768
10769        if (found_record)
10770                return buffer_record;
10771        else
10772                return NULL;
10773}
10774