linux/drivers/staging/media/atomisp/pci/sh_css.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Support for Intel Camera Imaging ISP subsystem.
   4 * Copyright (c) 2015, Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 */
  15
  16/*! \file */
  17#include <linux/mm.h>
  18#include <linux/slab.h>
  19#include <linux/vmalloc.h>
  20
  21#include "hmm.h"
  22
  23#include "ia_css.h"
  24#include "sh_css_hrt.h"         /* only for file 2 MIPI */
  25#include "ia_css_buffer.h"
  26#include "ia_css_binary.h"
  27#include "sh_css_internal.h"
  28#include "sh_css_mipi.h"
  29#include "sh_css_sp.h"          /* sh_css_sp_group */
  30#include "ia_css_isys.h"
  31#include "ia_css_frame.h"
  32#include "sh_css_defs.h"
  33#include "sh_css_firmware.h"
  34#include "sh_css_params.h"
  35#include "sh_css_params_internal.h"
  36#include "sh_css_param_shading.h"
  37#include "ia_css_refcount.h"
  38#include "ia_css_rmgr.h"
  39#include "ia_css_debug.h"
  40#include "ia_css_debug_pipe.h"
  41#include "ia_css_device_access.h"
  42#include "device_access.h"
  43#include "sh_css_legacy.h"
  44#include "ia_css_pipeline.h"
  45#include "ia_css_stream.h"
  46#include "sh_css_stream_format.h"
  47#include "ia_css_pipe.h"
  48#include "ia_css_util.h"
  49#include "ia_css_pipe_util.h"
  50#include "ia_css_pipe_binarydesc.h"
  51#include "ia_css_pipe_stagedesc.h"
  52
  53#include "tag.h"
  54#include "assert_support.h"
  55#include "math_support.h"
  56#include "sw_event_global.h"                    /* Event IDs.*/
  57#if !defined(ISP2401)
  58#include "ia_css_ifmtr.h"
  59#endif
  60#include "input_system.h"
  61#include "mmu_device.h"         /* mmu_set_page_table_base_index(), ... */
  62#include "ia_css_mmu_private.h" /* sh_css_mmu_set_page_table_base_index() */
  63#include "gdc_device.h"         /* HRT_GDC_N */
  64#include "dma.h"                /* dma_set_max_burst_size() */
  65#include "irq.h"                        /* virq */
  66#include "sp.h"                         /* cnd_sp_irq_enable() */
  67#include "isp.h"                        /* cnd_isp_irq_enable, ISP_VEC_NELEMS */
  68#include "gp_device.h"          /* gp_device_reg_store() */
  69#define __INLINE_GPIO__
  70#include "gpio.h"
  71#include "timed_ctrl.h"
  72#include "ia_css_inputfifo.h"
  73#define WITH_PC_MONITORING  0
  74
  75#define SH_CSS_VIDEO_BUFFER_ALIGNMENT 0
  76
  77#if WITH_PC_MONITORING
  78#define MULTIPLE_SAMPLES 1
  79#define NOF_SAMPLES      60
  80#include "linux/kthread.h"
  81#include "linux/sched.h"
  82#include "linux/delay.h"
  83#include "sh_css_metrics.h"
  84static int thread_alive;
  85#endif /* WITH_PC_MONITORING */
  86
  87#include "ia_css_spctrl.h"
  88#include "ia_css_version_data.h"
  89#include "sh_css_struct.h"
  90#include "ia_css_bufq.h"
  91#include "ia_css_timer.h" /* clock_value_t */
  92
  93#include "isp/modes/interface/input_buf.isp.h"
  94
  95/* Name of the sp program: should not be built-in */
  96#define SP_PROG_NAME "sp"
  97/* Size of Refcount List */
  98#define REFCOUNT_SIZE 1000
  99
 100/* for JPEG, we don't know the length of the image upfront,
 101 * but since we support sensor upto 16MP, we take this as
 102 * upper limit.
 103 */
 104#define JPEG_BYTES (16 * 1024 * 1024)
 105
 106#define STATS_ENABLED(stage) (stage && stage->binary && stage->binary->info && \
 107        (stage->binary->info->sp.enable.s3a || stage->binary->info->sp.enable.dis))
 108
 109struct sh_css my_css;
 110
 111int  __printf(1, 0) (*sh_css_printf)(const char *fmt, va_list args) = NULL;
 112
 113/* modes of work: stream_create and stream_destroy will update the save/restore data
 114   only when in working mode, not suspend/resume
 115*/
 116enum ia_sh_css_modes {
 117        sh_css_mode_none = 0,
 118        sh_css_mode_working,
 119        sh_css_mode_suspend,
 120        sh_css_mode_resume
 121};
 122
 123/* a stream seed, to save and restore the stream data.
 124   the stream seed contains all the data required to "grow" the seed again after it was closed.
 125*/
 126struct sh_css_stream_seed {
 127        struct ia_css_stream
 128                **orig_stream;                /* pointer to restore the original handle */
 129        struct ia_css_stream            *stream;                      /* handle, used as ID too.*/
 130        struct ia_css_stream_config     stream_config;                          /* stream config struct */
 131        int                             num_pipes;
 132        struct ia_css_pipe              *pipes[IA_CSS_PIPE_ID_NUM];                     /* pipe handles */
 133        struct ia_css_pipe
 134                **orig_pipes[IA_CSS_PIPE_ID_NUM];       /* pointer to restore original handle */
 135        struct ia_css_pipe_config
 136                pipe_config[IA_CSS_PIPE_ID_NUM];        /* pipe config structs */
 137};
 138
 139#define MAX_ACTIVE_STREAMS      5
 140/* A global struct for save/restore to hold all the data that should sustain power-down:
 141   MMU base, IRQ type, env for routines, binary loaded FW and the stream seeds.
 142*/
 143struct sh_css_save {
 144        enum ia_sh_css_modes            mode;
 145        u32                    mmu_base;                                /* the last mmu_base */
 146        enum ia_css_irq_type           irq_type;
 147        struct sh_css_stream_seed      stream_seeds[MAX_ACTIVE_STREAMS];
 148        struct ia_css_fw               *loaded_fw;                              /* fw struct previously loaded */
 149        struct ia_css_env              driver_env;                              /* driver-supplied env copy */
 150};
 151
 152static bool my_css_save_initialized;    /* if my_css_save was initialized */
 153static struct sh_css_save my_css_save;
 154
 155/* pqiao NOTICE: this is for css internal buffer recycling when stopping pipeline,
 156   this array is temporary and will be replaced by resource manager*/
 157/* Taking the biggest Size for number of Elements */
 158#define MAX_HMM_BUFFER_NUM      \
 159        (SH_CSS_MAX_NUM_QUEUES * (IA_CSS_NUM_ELEMS_SP2HOST_BUFFER_QUEUE + 2))
 160
 161struct sh_css_hmm_buffer_record {
 162        bool in_use;
 163        enum ia_css_buffer_type type;
 164        struct ia_css_rmgr_vbuf_handle *h_vbuf;
 165        hrt_address kernel_ptr;
 166};
 167
 168static struct sh_css_hmm_buffer_record hmm_buffer_record[MAX_HMM_BUFFER_NUM];
 169
 170#define GPIO_FLASH_PIN_MASK BIT(HIVE_GPIO_STROBE_TRIGGER_PIN)
 171
 172static bool fw_explicitly_loaded;
 173
 174/*
 175 * Local prototypes
 176 */
 177
 178static int
 179allocate_delay_frames(struct ia_css_pipe *pipe);
 180
 181static int
 182sh_css_pipe_start(struct ia_css_stream *stream);
 183
 184/* ISP 2401 */
 185/*
 186 * @brief Stop all "ia_css_pipe" instances in the target
 187 * "ia_css_stream" instance.
 188 *
 189 * @param[in] stream    Point to the target "ia_css_stream" instance.
 190 *
 191 * @return
 192 * - 0, if the "stop" requests have been successfully sent out.
 193 * - CSS error code, otherwise.
 194 *
 195 *
 196 * NOTE
 197 * This API sends the "stop" requests to the "ia_css_pipe"
 198 * instances in the same "ia_css_stream" instance. It will
 199 * return without waiting for all "ia_css_pipe" instatnces
 200 * being stopped.
 201 */
 202static int
 203sh_css_pipes_stop(struct ia_css_stream *stream);
 204
 205/*
 206 * @brief Check if all "ia_css_pipe" instances in the target
 207 * "ia_css_stream" instance have stopped.
 208 *
 209 * @param[in] stream    Point to the target "ia_css_stream" instance.
 210 *
 211 * @return
 212 * - true, if all "ia_css_pipe" instances in the target "ia_css_stream"
 213 *   instance have ben stopped.
 214 * - false, otherwise.
 215 */
 216/* ISP 2401 */
 217static bool
 218sh_css_pipes_have_stopped(struct ia_css_stream *stream);
 219
 220/* ISP 2401 */
 221static int
 222ia_css_pipe_check_format(struct ia_css_pipe *pipe,
 223                         enum ia_css_frame_format format);
 224
 225/* ISP 2401 */
 226static int
 227check_pipe_resolutions(const struct ia_css_pipe *pipe);
 228
 229static int
 230ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
 231                           struct ia_css_fw_info *firmware);
 232
 233static void
 234ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
 235                             struct ia_css_fw_info *firmware);
 236static void
 237ia_css_reset_defaults(struct sh_css *css);
 238
 239static void
 240sh_css_init_host_sp_control_vars(void);
 241
 242static int
 243set_num_primary_stages(unsigned int *num, enum ia_css_pipe_version version);
 244
 245static bool
 246need_capture_pp(const struct ia_css_pipe *pipe);
 247
 248static bool
 249need_yuv_scaler_stage(const struct ia_css_pipe *pipe);
 250
 251static int ia_css_pipe_create_cas_scaler_desc_single_output(
 252    struct ia_css_frame_info *cas_scaler_in_info,
 253    struct ia_css_frame_info *cas_scaler_out_info,
 254    struct ia_css_frame_info *cas_scaler_vf_info,
 255    struct ia_css_cas_binary_descr *descr);
 256
 257static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
 258        *descr);
 259
 260static bool
 261need_downscaling(const struct ia_css_resolution in_res,
 262                 const struct ia_css_resolution out_res);
 263
 264static bool need_capt_ldc(const struct ia_css_pipe *pipe);
 265
 266static int
 267sh_css_pipe_load_binaries(struct ia_css_pipe *pipe);
 268
 269static
 270int sh_css_pipe_get_viewfinder_frame_info(
 271    struct ia_css_pipe *pipe,
 272    struct ia_css_frame_info *info,
 273    unsigned int idx);
 274
 275static int
 276sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
 277                                  struct ia_css_frame_info *info,
 278                                  unsigned int idx);
 279
 280static int
 281capture_start(struct ia_css_pipe *pipe);
 282
 283static int
 284video_start(struct ia_css_pipe *pipe);
 285
 286static int
 287preview_start(struct ia_css_pipe *pipe);
 288
 289static int
 290yuvpp_start(struct ia_css_pipe *pipe);
 291
 292static bool copy_on_sp(struct ia_css_pipe *pipe);
 293
 294static int
 295init_vf_frameinfo_defaults(struct ia_css_pipe *pipe,
 296                           struct ia_css_frame *vf_frame, unsigned int idx);
 297
 298static int
 299init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
 300                                  struct ia_css_frame *frame, enum ia_css_frame_format format);
 301
 302static int
 303init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
 304                            struct ia_css_frame *out_frame, unsigned int idx);
 305
 306static int
 307sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
 308                              const void *acc_fw);
 309
 310static int
 311alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time);
 312
 313static void
 314pipe_global_init(void);
 315
 316static int
 317pipe_generate_pipe_num(const struct ia_css_pipe *pipe,
 318                       unsigned int *pipe_number);
 319
 320static void
 321pipe_release_pipe_num(unsigned int pipe_num);
 322
 323static int
 324create_host_pipeline_structure(struct ia_css_stream *stream);
 325
 326static int
 327create_host_pipeline(struct ia_css_stream *stream);
 328
 329static int
 330create_host_preview_pipeline(struct ia_css_pipe *pipe);
 331
 332static int
 333create_host_video_pipeline(struct ia_css_pipe *pipe);
 334
 335static int
 336create_host_copy_pipeline(struct ia_css_pipe *pipe,
 337                          unsigned int max_input_width,
 338                          struct ia_css_frame *out_frame);
 339
 340static int
 341create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe);
 342
 343static int
 344create_host_capture_pipeline(struct ia_css_pipe *pipe);
 345
 346static int
 347create_host_yuvpp_pipeline(struct ia_css_pipe *pipe);
 348
 349static int
 350create_host_acc_pipeline(struct ia_css_pipe *pipe);
 351
 352static unsigned int
 353sh_css_get_sw_interrupt_value(unsigned int irq);
 354
 355static struct ia_css_binary *ia_css_pipe_get_shading_correction_binary(
 356    const struct ia_css_pipe *pipe);
 357
 358static struct ia_css_binary *
 359ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe);
 360
 361static struct ia_css_binary *
 362ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe);
 363
 364static void
 365sh_css_hmm_buffer_record_init(void);
 366
 367static void
 368sh_css_hmm_buffer_record_uninit(void);
 369
 370static void
 371sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record);
 372
 373static struct sh_css_hmm_buffer_record
 374*sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf,
 375                                  enum ia_css_buffer_type type,
 376                                  hrt_address kernel_ptr);
 377
 378static struct sh_css_hmm_buffer_record
 379*sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr,
 380                                   enum ia_css_buffer_type type);
 381
 382void
 383ia_css_get_acc_configs(
 384    struct ia_css_pipe *pipe,
 385    struct ia_css_isp_config *config);
 386
 387#if CONFIG_ON_FRAME_ENQUEUE()
 388static int set_config_on_frame_enqueue(struct ia_css_frame_info
 389        *info, struct frame_data_wrapper *frame);
 390#endif
 391
 392#ifdef ISP2401
 393static unsigned int get_crop_lines_for_bayer_order(const struct
 394        ia_css_stream_config *config);
 395static unsigned int get_crop_columns_for_bayer_order(const struct
 396        ia_css_stream_config *config);
 397static void get_pipe_extra_pixel(struct ia_css_pipe *pipe,
 398                                 unsigned int *extra_row, unsigned int *extra_column);
 399static int
 400aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
 401                       struct ia_css_pipe *pipes[],
 402                       bool *do_crop_status);
 403
 404static bool
 405aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe);
 406
 407static int
 408aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
 409                  struct ia_css_resolution *effective_res);
 410#endif
 411
 412static void
 413sh_css_pipe_free_shading_table(struct ia_css_pipe *pipe)
 414{
 415        if (!pipe) {
 416                IA_CSS_ERROR("NULL input parameter");
 417                return;
 418        }
 419
 420        if (pipe->shading_table)
 421                ia_css_shading_table_free(pipe->shading_table);
 422        pipe->shading_table = NULL;
 423}
 424
 425static enum ia_css_frame_format yuv420_copy_formats[] = {
 426        IA_CSS_FRAME_FORMAT_NV12,
 427        IA_CSS_FRAME_FORMAT_NV21,
 428        IA_CSS_FRAME_FORMAT_YV12,
 429        IA_CSS_FRAME_FORMAT_YUV420,
 430        IA_CSS_FRAME_FORMAT_YUV420_16,
 431        IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8,
 432        IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8
 433};
 434
 435static enum ia_css_frame_format yuv422_copy_formats[] = {
 436        IA_CSS_FRAME_FORMAT_NV12,
 437        IA_CSS_FRAME_FORMAT_NV16,
 438        IA_CSS_FRAME_FORMAT_NV21,
 439        IA_CSS_FRAME_FORMAT_NV61,
 440        IA_CSS_FRAME_FORMAT_YV12,
 441        IA_CSS_FRAME_FORMAT_YV16,
 442        IA_CSS_FRAME_FORMAT_YUV420,
 443        IA_CSS_FRAME_FORMAT_YUV420_16,
 444        IA_CSS_FRAME_FORMAT_YUV422,
 445        IA_CSS_FRAME_FORMAT_YUV422_16,
 446        IA_CSS_FRAME_FORMAT_UYVY,
 447        IA_CSS_FRAME_FORMAT_YUYV
 448};
 449
 450/* Verify whether the selected output format is can be produced
 451 * by the copy binary given the stream format.
 452 * */
 453static int
 454verify_copy_out_frame_format(struct ia_css_pipe *pipe)
 455{
 456        enum ia_css_frame_format out_fmt = pipe->output_info[0].format;
 457        unsigned int i, found = 0;
 458
 459        assert(pipe);
 460        assert(pipe->stream);
 461
 462        switch (pipe->stream->config.input_config.format) {
 463        case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:
 464        case ATOMISP_INPUT_FORMAT_YUV420_8:
 465                for (i = 0; i < ARRAY_SIZE(yuv420_copy_formats) && !found; i++)
 466                        found = (out_fmt == yuv420_copy_formats[i]);
 467                break;
 468        case ATOMISP_INPUT_FORMAT_YUV420_10:
 469        case ATOMISP_INPUT_FORMAT_YUV420_16:
 470                found = (out_fmt == IA_CSS_FRAME_FORMAT_YUV420_16);
 471                break;
 472        case ATOMISP_INPUT_FORMAT_YUV422_8:
 473                for (i = 0; i < ARRAY_SIZE(yuv422_copy_formats) && !found; i++)
 474                        found = (out_fmt == yuv422_copy_formats[i]);
 475                break;
 476        case ATOMISP_INPUT_FORMAT_YUV422_10:
 477        case ATOMISP_INPUT_FORMAT_YUV422_16:
 478                found = (out_fmt == IA_CSS_FRAME_FORMAT_YUV422_16 ||
 479                         out_fmt == IA_CSS_FRAME_FORMAT_YUV420_16);
 480                break;
 481        case ATOMISP_INPUT_FORMAT_RGB_444:
 482        case ATOMISP_INPUT_FORMAT_RGB_555:
 483        case ATOMISP_INPUT_FORMAT_RGB_565:
 484                found = (out_fmt == IA_CSS_FRAME_FORMAT_RGBA888 ||
 485                         out_fmt == IA_CSS_FRAME_FORMAT_RGB565);
 486                break;
 487        case ATOMISP_INPUT_FORMAT_RGB_666:
 488        case ATOMISP_INPUT_FORMAT_RGB_888:
 489                found = (out_fmt == IA_CSS_FRAME_FORMAT_RGBA888 ||
 490                         out_fmt == IA_CSS_FRAME_FORMAT_YUV420);
 491                break;
 492        case ATOMISP_INPUT_FORMAT_RAW_6:
 493        case ATOMISP_INPUT_FORMAT_RAW_7:
 494        case ATOMISP_INPUT_FORMAT_RAW_8:
 495        case ATOMISP_INPUT_FORMAT_RAW_10:
 496        case ATOMISP_INPUT_FORMAT_RAW_12:
 497        case ATOMISP_INPUT_FORMAT_RAW_14:
 498        case ATOMISP_INPUT_FORMAT_RAW_16:
 499                found = (out_fmt == IA_CSS_FRAME_FORMAT_RAW) ||
 500                (out_fmt == IA_CSS_FRAME_FORMAT_RAW_PACKED);
 501                break;
 502        case ATOMISP_INPUT_FORMAT_BINARY_8:
 503                found = (out_fmt == IA_CSS_FRAME_FORMAT_BINARY_8);
 504                break;
 505        default:
 506                break;
 507        }
 508        if (!found)
 509                return -EINVAL;
 510        return 0;
 511}
 512
 513unsigned int
 514ia_css_stream_input_format_bits_per_pixel(struct ia_css_stream *stream)
 515{
 516        int bpp = 0;
 517
 518        if (stream)
 519                bpp = ia_css_util_input_format_bpp(stream->config.input_config.format,
 520                                                   stream->config.pixels_per_clock == 2);
 521
 522        return bpp;
 523}
 524
 525#define GP_ISEL_TPG_MODE 0x90058
 526
 527#if !defined(ISP2401)
 528static int
 529sh_css_config_input_network(struct ia_css_stream *stream)
 530{
 531        unsigned int fmt_type;
 532        struct ia_css_pipe *pipe = stream->last_pipe;
 533        struct ia_css_binary *binary = NULL;
 534        int err = 0;
 535
 536        assert(stream);
 537        assert(pipe);
 538
 539        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
 540                            "sh_css_config_input_network() enter:\n");
 541
 542        if (pipe->pipeline.stages)
 543                binary = pipe->pipeline.stages->binary;
 544
 545        err = ia_css_isys_convert_stream_format_to_mipi_format(
 546            stream->config.input_config.format,
 547            stream->csi_rx_config.comp,
 548            &fmt_type);
 549        if (err)
 550                return err;
 551        sh_css_sp_program_input_circuit(fmt_type,
 552                                        stream->config.channel_id,
 553                                        stream->config.mode);
 554
 555        if ((binary && (binary->online || stream->config.continuous)) ||
 556            pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
 557                err = ia_css_ifmtr_configure(&stream->config,
 558                                             binary);
 559                if (err)
 560                        return err;
 561        }
 562
 563        if (stream->config.mode == IA_CSS_INPUT_MODE_TPG ||
 564            stream->config.mode == IA_CSS_INPUT_MODE_PRBS) {
 565                unsigned int hblank_cycles = 100,
 566                vblank_lines = 6,
 567                width,
 568                height,
 569                vblank_cycles;
 570                width  = (stream->config.input_config.input_res.width) / (1 +
 571                        (stream->config.pixels_per_clock == 2));
 572                height = stream->config.input_config.input_res.height;
 573                vblank_cycles = vblank_lines * (width + hblank_cycles);
 574                sh_css_sp_configure_sync_gen(width, height, hblank_cycles,
 575                                             vblank_cycles);
 576                if (!IS_ISP2401) {
 577                        if (pipe->stream->config.mode == IA_CSS_INPUT_MODE_TPG) {
 578                                /* TODO: move define to proper file in tools */
 579                                ia_css_device_store_uint32(GP_ISEL_TPG_MODE, 0);
 580                        }
 581                }
 582        }
 583        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
 584                            "sh_css_config_input_network() leave:\n");
 585        return 0;
 586}
 587#elif defined(ISP2401)
 588static unsigned int csi2_protocol_calculate_max_subpixels_per_line(
 589    enum atomisp_input_format   format,
 590    unsigned int                        pixels_per_line)
 591{
 592        unsigned int rval;
 593
 594        switch (format) {
 595        case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:
 596                /*
 597                 * The frame format layout is shown below.
 598                 *
 599                 *              Line    0:      UYY0 UYY0 ... UYY0
 600                 *              Line    1:      VYY0 VYY0 ... VYY0
 601                 *              Line    2:      UYY0 UYY0 ... UYY0
 602                 *              Line    3:      VYY0 VYY0 ... VYY0
 603                 *              ...
 604                 *              Line (n-2):     UYY0 UYY0 ... UYY0
 605                 *              Line (n-1):     VYY0 VYY0 ... VYY0
 606                 *
 607                 *      In this frame format, the even-line is
 608                 *      as wide as the odd-line.
 609                 *      The 0 is introduced by the input system
 610                 *      (mipi backend).
 611                 */
 612                rval = pixels_per_line * 2;
 613                break;
 614        case ATOMISP_INPUT_FORMAT_YUV420_8:
 615        case ATOMISP_INPUT_FORMAT_YUV420_10:
 616        case ATOMISP_INPUT_FORMAT_YUV420_16:
 617                /*
 618                 * The frame format layout is shown below.
 619                 *
 620                 *              Line    0:      YYYY YYYY ... YYYY
 621                 *              Line    1:      UYVY UYVY ... UYVY UYVY
 622                 *              Line    2:      YYYY YYYY ... YYYY
 623                 *              Line    3:      UYVY UYVY ... UYVY UYVY
 624                 *              ...
 625                 *              Line (n-2):     YYYY YYYY ... YYYY
 626                 *              Line (n-1):     UYVY UYVY ... UYVY UYVY
 627                 *
 628                 * In this frame format, the odd-line is twice
 629                 * wider than the even-line.
 630                 */
 631                rval = pixels_per_line * 2;
 632                break;
 633        case ATOMISP_INPUT_FORMAT_YUV422_8:
 634        case ATOMISP_INPUT_FORMAT_YUV422_10:
 635        case ATOMISP_INPUT_FORMAT_YUV422_16:
 636                /*
 637                 * The frame format layout is shown below.
 638                 *
 639                 *              Line    0:      UYVY UYVY ... UYVY
 640                 *              Line    1:      UYVY UYVY ... UYVY
 641                 *              Line    2:      UYVY UYVY ... UYVY
 642                 *              Line    3:      UYVY UYVY ... UYVY
 643                 *              ...
 644                 *              Line (n-2):     UYVY UYVY ... UYVY
 645                 *              Line (n-1):     UYVY UYVY ... UYVY
 646                 *
 647                 * In this frame format, the even-line is
 648                 * as wide as the odd-line.
 649                 */
 650                rval = pixels_per_line * 2;
 651                break;
 652        case ATOMISP_INPUT_FORMAT_RGB_444:
 653        case ATOMISP_INPUT_FORMAT_RGB_555:
 654        case ATOMISP_INPUT_FORMAT_RGB_565:
 655        case ATOMISP_INPUT_FORMAT_RGB_666:
 656        case ATOMISP_INPUT_FORMAT_RGB_888:
 657                /*
 658                 * The frame format layout is shown below.
 659                 *
 660                 *              Line    0:      ABGR ABGR ... ABGR
 661                 *              Line    1:      ABGR ABGR ... ABGR
 662                 *              Line    2:      ABGR ABGR ... ABGR
 663                 *              Line    3:      ABGR ABGR ... ABGR
 664                 *              ...
 665                 *              Line (n-2):     ABGR ABGR ... ABGR
 666                 *              Line (n-1):     ABGR ABGR ... ABGR
 667                 *
 668                 * In this frame format, the even-line is
 669                 * as wide as the odd-line.
 670                 */
 671                rval = pixels_per_line * 4;
 672                break;
 673        case ATOMISP_INPUT_FORMAT_RAW_6:
 674        case ATOMISP_INPUT_FORMAT_RAW_7:
 675        case ATOMISP_INPUT_FORMAT_RAW_8:
 676        case ATOMISP_INPUT_FORMAT_RAW_10:
 677        case ATOMISP_INPUT_FORMAT_RAW_12:
 678        case ATOMISP_INPUT_FORMAT_RAW_14:
 679        case ATOMISP_INPUT_FORMAT_RAW_16:
 680        case ATOMISP_INPUT_FORMAT_BINARY_8:
 681        case ATOMISP_INPUT_FORMAT_USER_DEF1:
 682        case ATOMISP_INPUT_FORMAT_USER_DEF2:
 683        case ATOMISP_INPUT_FORMAT_USER_DEF3:
 684        case ATOMISP_INPUT_FORMAT_USER_DEF4:
 685        case ATOMISP_INPUT_FORMAT_USER_DEF5:
 686        case ATOMISP_INPUT_FORMAT_USER_DEF6:
 687        case ATOMISP_INPUT_FORMAT_USER_DEF7:
 688        case ATOMISP_INPUT_FORMAT_USER_DEF8:
 689                /*
 690                 * The frame format layout is shown below.
 691                 *
 692                 *              Line    0:      Pixel Pixel ... Pixel
 693                 *              Line    1:      Pixel Pixel ... Pixel
 694                 *              Line    2:      Pixel Pixel ... Pixel
 695                 *              Line    3:      Pixel Pixel ... Pixel
 696                 *              ...
 697                 *              Line (n-2):     Pixel Pixel ... Pixel
 698                 *              Line (n-1):     Pixel Pixel ... Pixel
 699                 *
 700                 * In this frame format, the even-line is
 701                 * as wide as the odd-line.
 702                 */
 703                rval = pixels_per_line;
 704                break;
 705        default:
 706                rval = 0;
 707                break;
 708        }
 709
 710        return rval;
 711}
 712
 713static bool sh_css_translate_stream_cfg_to_input_system_input_port_id(
 714    struct ia_css_stream_config *stream_cfg,
 715    ia_css_isys_descr_t *isys_stream_descr)
 716{
 717        bool rc;
 718
 719        rc = true;
 720        switch (stream_cfg->mode) {
 721        case IA_CSS_INPUT_MODE_TPG:
 722
 723                if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID0)
 724                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID;
 725                else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID1)
 726                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID;
 727                else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID2)
 728                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID;
 729
 730                break;
 731        case IA_CSS_INPUT_MODE_PRBS:
 732
 733                if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID0)
 734                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID;
 735                else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID1)
 736                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID;
 737                else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID2)
 738                        isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID;
 739
 740                break;
 741        case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
 742
 743                if (stream_cfg->source.port.port == MIPI_PORT0_ID)
 744                        isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT0_ID;
 745                else if (stream_cfg->source.port.port == MIPI_PORT1_ID)
 746                        isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT1_ID;
 747                else if (stream_cfg->source.port.port == MIPI_PORT2_ID)
 748                        isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT2_ID;
 749
 750                break;
 751        default:
 752                rc = false;
 753                break;
 754        }
 755
 756        return rc;
 757}
 758
 759static bool sh_css_translate_stream_cfg_to_input_system_input_port_type(
 760    struct ia_css_stream_config *stream_cfg,
 761    ia_css_isys_descr_t *isys_stream_descr)
 762{
 763        bool rc;
 764
 765        rc = true;
 766        switch (stream_cfg->mode) {
 767        case IA_CSS_INPUT_MODE_TPG:
 768
 769                isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_TPG;
 770
 771                break;
 772        case IA_CSS_INPUT_MODE_PRBS:
 773
 774                isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_PRBS;
 775
 776                break;
 777        case IA_CSS_INPUT_MODE_SENSOR:
 778        case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
 779
 780                isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_SENSOR;
 781                break;
 782
 783        default:
 784                rc = false;
 785                break;
 786        }
 787
 788        return rc;
 789}
 790
 791static bool sh_css_translate_stream_cfg_to_input_system_input_port_attr(
 792    struct ia_css_stream_config *stream_cfg,
 793    ia_css_isys_descr_t *isys_stream_descr,
 794    int isys_stream_idx)
 795{
 796        bool rc;
 797
 798        rc = true;
 799        switch (stream_cfg->mode) {
 800        case IA_CSS_INPUT_MODE_TPG:
 801                if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_RAMP)
 802                        isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_RAMP;
 803                else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_CHECKERBOARD)
 804                        isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_CHBO;
 805                else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_MONO)
 806                        isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_MONO;
 807                else
 808                        rc = false;
 809
 810                /*
 811                 * TODO
 812                 * - Make "color_cfg" as part of "ia_css_tpg_config".
 813                 */
 814                isys_stream_descr->tpg_port_attr.color_cfg.R1 = 51;
 815                isys_stream_descr->tpg_port_attr.color_cfg.G1 = 102;
 816                isys_stream_descr->tpg_port_attr.color_cfg.B1 = 255;
 817                isys_stream_descr->tpg_port_attr.color_cfg.R2 = 0;
 818                isys_stream_descr->tpg_port_attr.color_cfg.G2 = 100;
 819                isys_stream_descr->tpg_port_attr.color_cfg.B2 = 160;
 820
 821                isys_stream_descr->tpg_port_attr.mask_cfg.h_mask =
 822                    stream_cfg->source.tpg.x_mask;
 823                isys_stream_descr->tpg_port_attr.mask_cfg.v_mask =
 824                    stream_cfg->source.tpg.y_mask;
 825                isys_stream_descr->tpg_port_attr.mask_cfg.hv_mask =
 826                    stream_cfg->source.tpg.xy_mask;
 827
 828                isys_stream_descr->tpg_port_attr.delta_cfg.h_delta =
 829                    stream_cfg->source.tpg.x_delta;
 830                isys_stream_descr->tpg_port_attr.delta_cfg.v_delta =
 831                    stream_cfg->source.tpg.y_delta;
 832
 833                /*
 834                 * TODO
 835                 * - Make "sync_gen_cfg" as part of "ia_css_tpg_config".
 836                 */
 837                isys_stream_descr->tpg_port_attr.sync_gen_cfg.hblank_cycles = 100;
 838                isys_stream_descr->tpg_port_attr.sync_gen_cfg.vblank_cycles = 100;
 839                isys_stream_descr->tpg_port_attr.sync_gen_cfg.pixels_per_clock =
 840                    stream_cfg->pixels_per_clock;
 841                isys_stream_descr->tpg_port_attr.sync_gen_cfg.nr_of_frames = (uint32_t)~(0x0);
 842                isys_stream_descr->tpg_port_attr.sync_gen_cfg.pixels_per_line =
 843                    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.width;
 844                isys_stream_descr->tpg_port_attr.sync_gen_cfg.lines_per_frame =
 845                    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.height;
 846
 847                break;
 848        case IA_CSS_INPUT_MODE_PRBS:
 849
 850                isys_stream_descr->prbs_port_attr.seed0 = stream_cfg->source.prbs.seed;
 851                isys_stream_descr->prbs_port_attr.seed1 = stream_cfg->source.prbs.seed1;
 852
 853                /*
 854                 * TODO
 855                 * - Make "sync_gen_cfg" as part of "ia_css_prbs_config".
 856                 */
 857                isys_stream_descr->prbs_port_attr.sync_gen_cfg.hblank_cycles = 100;
 858                isys_stream_descr->prbs_port_attr.sync_gen_cfg.vblank_cycles = 100;
 859                isys_stream_descr->prbs_port_attr.sync_gen_cfg.pixels_per_clock =
 860                    stream_cfg->pixels_per_clock;
 861                isys_stream_descr->prbs_port_attr.sync_gen_cfg.nr_of_frames = (uint32_t)~(0x0);
 862                isys_stream_descr->prbs_port_attr.sync_gen_cfg.pixels_per_line =
 863                    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.width;
 864                isys_stream_descr->prbs_port_attr.sync_gen_cfg.lines_per_frame =
 865                    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.height;
 866
 867                break;
 868        case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: {
 869                int err;
 870                unsigned int fmt_type;
 871
 872                err = ia_css_isys_convert_stream_format_to_mipi_format(
 873                          stream_cfg->isys_config[isys_stream_idx].format,
 874                          MIPI_PREDICTOR_NONE,
 875                          &fmt_type);
 876                if (err)
 877                        rc = false;
 878
 879                isys_stream_descr->csi_port_attr.active_lanes =
 880                    stream_cfg->source.port.num_lanes;
 881                isys_stream_descr->csi_port_attr.fmt_type = fmt_type;
 882                isys_stream_descr->csi_port_attr.ch_id = stream_cfg->channel_id;
 883#ifdef ISP2401
 884                isys_stream_descr->online = stream_cfg->online;
 885#endif
 886                err |= ia_css_isys_convert_compressed_format(
 887                           &stream_cfg->source.port.compression,
 888                           isys_stream_descr);
 889                if (err)
 890                        rc = false;
 891
 892                /* metadata */
 893                isys_stream_descr->metadata.enable = false;
 894                if (stream_cfg->metadata_config.resolution.height > 0) {
 895                        err = ia_css_isys_convert_stream_format_to_mipi_format(
 896                                  stream_cfg->metadata_config.data_type,
 897                                  MIPI_PREDICTOR_NONE,
 898                                  &fmt_type);
 899                        if (err)
 900                                rc = false;
 901                        isys_stream_descr->metadata.fmt_type = fmt_type;
 902                        isys_stream_descr->metadata.bits_per_pixel =
 903                            ia_css_util_input_format_bpp(stream_cfg->metadata_config.data_type, true);
 904                        isys_stream_descr->metadata.pixels_per_line =
 905                            stream_cfg->metadata_config.resolution.width;
 906                        isys_stream_descr->metadata.lines_per_frame =
 907                            stream_cfg->metadata_config.resolution.height;
 908#ifdef ISP2401
 909                        /* For new input system, number of str2mmio requests must be even.
 910                         * So we round up number of metadata lines to be even. */
 911                        if (isys_stream_descr->metadata.lines_per_frame > 0)
 912                                isys_stream_descr->metadata.lines_per_frame +=
 913                                    (isys_stream_descr->metadata.lines_per_frame & 1);
 914#endif
 915                        isys_stream_descr->metadata.align_req_in_bytes =
 916                            ia_css_csi2_calculate_input_system_alignment(
 917                                stream_cfg->metadata_config.data_type);
 918                        isys_stream_descr->metadata.enable = true;
 919                }
 920
 921                break;
 922        }
 923        default:
 924                rc = false;
 925                break;
 926        }
 927
 928        return rc;
 929}
 930
 931static bool sh_css_translate_stream_cfg_to_input_system_input_port_resolution(
 932    struct ia_css_stream_config *stream_cfg,
 933    ia_css_isys_descr_t *isys_stream_descr,
 934    int isys_stream_idx)
 935{
 936        unsigned int bits_per_subpixel;
 937        unsigned int max_subpixels_per_line;
 938        unsigned int lines_per_frame;
 939        unsigned int align_req_in_bytes;
 940        enum atomisp_input_format fmt_type;
 941
 942        fmt_type = stream_cfg->isys_config[isys_stream_idx].format;
 943        if ((stream_cfg->mode == IA_CSS_INPUT_MODE_SENSOR ||
 944             stream_cfg->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) &&
 945            stream_cfg->source.port.compression.type != IA_CSS_CSI2_COMPRESSION_TYPE_NONE) {
 946                if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
 947                    UNCOMPRESSED_BITS_PER_PIXEL_10)
 948                        fmt_type = ATOMISP_INPUT_FORMAT_RAW_10;
 949                else if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
 950                           UNCOMPRESSED_BITS_PER_PIXEL_12)
 951                        fmt_type = ATOMISP_INPUT_FORMAT_RAW_12;
 952                else
 953                        return false;
 954        }
 955
 956        bits_per_subpixel =
 957            sh_css_stream_format_2_bits_per_subpixel(fmt_type);
 958        if (bits_per_subpixel == 0)
 959                return false;
 960
 961        max_subpixels_per_line =
 962            csi2_protocol_calculate_max_subpixels_per_line(fmt_type,
 963                    stream_cfg->isys_config[isys_stream_idx].input_res.width);
 964        if (max_subpixels_per_line == 0)
 965                return false;
 966
 967        lines_per_frame = stream_cfg->isys_config[isys_stream_idx].input_res.height;
 968        if (lines_per_frame == 0)
 969                return false;
 970
 971        align_req_in_bytes = ia_css_csi2_calculate_input_system_alignment(fmt_type);
 972
 973        /* HW needs subpixel info for their settings */
 974        isys_stream_descr->input_port_resolution.bits_per_pixel = bits_per_subpixel;
 975        isys_stream_descr->input_port_resolution.pixels_per_line =
 976            max_subpixels_per_line;
 977        isys_stream_descr->input_port_resolution.lines_per_frame = lines_per_frame;
 978        isys_stream_descr->input_port_resolution.align_req_in_bytes =
 979            align_req_in_bytes;
 980
 981        return true;
 982}
 983
 984static bool sh_css_translate_stream_cfg_to_isys_stream_descr(
 985    struct ia_css_stream_config *stream_cfg,
 986    bool early_polling,
 987    ia_css_isys_descr_t *isys_stream_descr,
 988    int isys_stream_idx)
 989{
 990        bool rc;
 991
 992        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
 993                            "sh_css_translate_stream_cfg_to_isys_stream_descr() enter:\n");
 994        rc  = sh_css_translate_stream_cfg_to_input_system_input_port_id(stream_cfg,
 995                isys_stream_descr);
 996        rc &= sh_css_translate_stream_cfg_to_input_system_input_port_type(stream_cfg,
 997                isys_stream_descr);
 998        rc &= sh_css_translate_stream_cfg_to_input_system_input_port_attr(stream_cfg,
 999                isys_stream_descr, isys_stream_idx);
1000        rc &= sh_css_translate_stream_cfg_to_input_system_input_port_resolution(
1001                  stream_cfg, isys_stream_descr, isys_stream_idx);
1002
1003        isys_stream_descr->raw_packed = stream_cfg->pack_raw_pixels;
1004        isys_stream_descr->linked_isys_stream_id = (int8_t)
1005                stream_cfg->isys_config[isys_stream_idx].linked_isys_stream_id;
1006        /*
1007         * Early polling is required for timestamp accuracy in certain case.
1008         * The ISYS HW polling is started on
1009         * ia_css_isys_stream_capture_indication() instead of
1010         * ia_css_pipeline_sp_wait_for_isys_stream_N() as isp processing of
1011         * capture takes longer than getting an ISYS frame
1012         *
1013         * Only 2401 relevant ??
1014         */
1015#if 0 // FIXME: NOT USED on Yocto Aero
1016        isys_stream_descr->polling_mode
1017            = early_polling ? INPUT_SYSTEM_POLL_ON_CAPTURE_REQUEST
1018              : INPUT_SYSTEM_POLL_ON_WAIT_FOR_FRAME;
1019        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
1020                            "sh_css_translate_stream_cfg_to_isys_stream_descr() leave:\n");
1021#endif
1022
1023        return rc;
1024}
1025
1026static bool sh_css_translate_binary_info_to_input_system_output_port_attr(
1027    struct ia_css_binary *binary,
1028    ia_css_isys_descr_t     *isys_stream_descr)
1029{
1030        if (!binary)
1031                return false;
1032
1033        isys_stream_descr->output_port_attr.left_padding = binary->left_padding;
1034        isys_stream_descr->output_port_attr.max_isp_input_width =
1035            binary->info->sp.input.max_width;
1036
1037        return true;
1038}
1039
1040static int
1041sh_css_config_input_network(struct ia_css_stream *stream)
1042{
1043        bool                                    rc;
1044        ia_css_isys_descr_t                     isys_stream_descr;
1045        unsigned int                            sp_thread_id;
1046        struct sh_css_sp_pipeline_terminal      *sp_pipeline_input_terminal;
1047        struct ia_css_pipe *pipe = NULL;
1048        struct ia_css_binary *binary = NULL;
1049        int i;
1050        u32 isys_stream_id;
1051        bool early_polling = false;
1052
1053        assert(stream);
1054        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
1055                            "sh_css_config_input_network() enter 0x%p:\n", stream);
1056
1057        if (stream->config.continuous) {
1058                if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE)
1059                        pipe = stream->last_pipe;
1060                else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_YUVPP)
1061                        pipe = stream->last_pipe;
1062                else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
1063                        pipe = stream->last_pipe->pipe_settings.preview.copy_pipe;
1064                else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO)
1065                        pipe = stream->last_pipe->pipe_settings.video.copy_pipe;
1066        } else {
1067                pipe = stream->last_pipe;
1068                if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
1069                        /*
1070                         * We need to poll the ISYS HW in capture_indication itself
1071                         * for "non-continuous" capture usecase for getting accurate
1072                         * isys frame capture timestamps.
1073                         * This is because the capturepipe propcessing takes longer
1074                         * to execute than the input system frame capture.
1075                         * 2401 specific
1076                         */
1077                        early_polling = true;
1078                }
1079        }
1080
1081        if (!pipe)
1082                return -EINVAL;
1083
1084        if (pipe->pipeline.stages)
1085                if (pipe->pipeline.stages->binary)
1086                        binary = pipe->pipeline.stages->binary;
1087
1088        if (binary) {
1089                /* this was being done in ifmtr in 2400.
1090                 * online and cont bypass the init_in_frameinfo_memory_defaults
1091                 * so need to do it here
1092                 */
1093                ia_css_get_crop_offsets(pipe, &binary->in_frame_info);
1094        }
1095
1096        /* get the SP thread id */
1097        rc = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &sp_thread_id);
1098        if (!rc)
1099                return -EINVAL;
1100        /* get the target input terminal */
1101        sp_pipeline_input_terminal = &sh_css_sp_group.pipe_io[sp_thread_id].input;
1102
1103        for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) {
1104                /* initialization */
1105                memset((void *)(&isys_stream_descr), 0, sizeof(ia_css_isys_descr_t));
1106                sp_pipeline_input_terminal->context.virtual_input_system_stream[i].valid = 0;
1107                sp_pipeline_input_terminal->ctrl.virtual_input_system_stream_cfg[i].valid = 0;
1108
1109                if (!stream->config.isys_config[i].valid)
1110                        continue;
1111
1112                /* translate the stream configuration to the Input System (2401) configuration */
1113                rc = sh_css_translate_stream_cfg_to_isys_stream_descr(
1114                         &stream->config,
1115                         early_polling,
1116                         &(isys_stream_descr), i);
1117
1118                if (stream->config.online) {
1119                        rc &= sh_css_translate_binary_info_to_input_system_output_port_attr(
1120                                  binary,
1121                                  &(isys_stream_descr));
1122                }
1123
1124                if (!rc)
1125                        return -EINVAL;
1126
1127                isys_stream_id = ia_css_isys_generate_stream_id(sp_thread_id, i);
1128
1129                /* create the virtual Input System (2401) */
1130                rc =  ia_css_isys_stream_create(
1131                          &(isys_stream_descr),
1132                          &sp_pipeline_input_terminal->context.virtual_input_system_stream[i],
1133                          isys_stream_id);
1134                if (!rc)
1135                        return -EINVAL;
1136
1137                /* calculate the configuration of the virtual Input System (2401) */
1138                rc = ia_css_isys_stream_calculate_cfg(
1139                         &sp_pipeline_input_terminal->context.virtual_input_system_stream[i],
1140                         &(isys_stream_descr),
1141                         &sp_pipeline_input_terminal->ctrl.virtual_input_system_stream_cfg[i]);
1142                if (!rc) {
1143                        ia_css_isys_stream_destroy(
1144                            &sp_pipeline_input_terminal->context.virtual_input_system_stream[i]);
1145                        return -EINVAL;
1146                }
1147        }
1148
1149        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
1150                            "sh_css_config_input_network() leave:\n");
1151
1152        return 0;
1153}
1154
1155static inline struct ia_css_pipe *stream_get_last_pipe(
1156    struct ia_css_stream *stream)
1157{
1158        struct ia_css_pipe *last_pipe = NULL;
1159
1160        if (stream)
1161                last_pipe = stream->last_pipe;
1162
1163        return last_pipe;
1164}
1165
1166static inline struct ia_css_pipe *stream_get_copy_pipe(
1167    struct ia_css_stream *stream)
1168{
1169        struct ia_css_pipe *copy_pipe = NULL;
1170        struct ia_css_pipe *last_pipe = NULL;
1171        enum ia_css_pipe_id pipe_id;
1172
1173        last_pipe = stream_get_last_pipe(stream);
1174
1175        if ((stream) &&
1176            (last_pipe) &&
1177            (stream->config.continuous)) {
1178                pipe_id = last_pipe->mode;
1179                switch (pipe_id) {
1180                case IA_CSS_PIPE_ID_PREVIEW:
1181                        copy_pipe = last_pipe->pipe_settings.preview.copy_pipe;
1182                        break;
1183                case IA_CSS_PIPE_ID_VIDEO:
1184                        copy_pipe = last_pipe->pipe_settings.video.copy_pipe;
1185                        break;
1186                default:
1187                        copy_pipe = NULL;
1188                        break;
1189                }
1190        }
1191
1192        return copy_pipe;
1193}
1194
1195static inline struct ia_css_pipe *stream_get_target_pipe(
1196    struct ia_css_stream *stream)
1197{
1198        struct ia_css_pipe *target_pipe;
1199
1200        /* get the pipe that consumes the stream */
1201        if (stream->config.continuous)
1202                target_pipe = stream_get_copy_pipe(stream);
1203        else
1204                target_pipe = stream_get_last_pipe(stream);
1205
1206        return target_pipe;
1207}
1208
1209static int stream_csi_rx_helper(
1210    struct ia_css_stream *stream,
1211    int (*func)(enum mipi_port_id, uint32_t))
1212{
1213        int retval = -EINVAL;
1214        u32 sp_thread_id, stream_id;
1215        bool rc;
1216        struct ia_css_pipe *target_pipe = NULL;
1217
1218        if ((!stream) || (stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR))
1219                goto exit;
1220
1221        target_pipe = stream_get_target_pipe(stream);
1222
1223        if (!target_pipe)
1224                goto exit;
1225
1226        rc = ia_css_pipeline_get_sp_thread_id(
1227                 ia_css_pipe_get_pipe_num(target_pipe),
1228                 &sp_thread_id);
1229
1230        if (!rc)
1231                goto exit;
1232
1233        /* (un)register all valid "virtual isys streams" within the ia_css_stream */
1234        stream_id = 0;
1235        do {
1236                if (stream->config.isys_config[stream_id].valid) {
1237                        u32 isys_stream_id = ia_css_isys_generate_stream_id(sp_thread_id, stream_id);
1238
1239                        retval = func(stream->config.source.port.port, isys_stream_id);
1240                }
1241                stream_id++;
1242        } while ((retval == 0) &&
1243                 (stream_id < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH));
1244
1245exit:
1246        return retval;
1247}
1248
1249static inline int stream_register_with_csi_rx(
1250    struct ia_css_stream *stream)
1251{
1252        return stream_csi_rx_helper(stream, ia_css_isys_csi_rx_register_stream);
1253}
1254
1255static inline int stream_unregister_with_csi_rx(
1256    struct ia_css_stream *stream)
1257{
1258        return stream_csi_rx_helper(stream, ia_css_isys_csi_rx_unregister_stream);
1259}
1260#endif
1261
1262#if WITH_PC_MONITORING
1263static struct task_struct *my_kthread;    /* Handle for the monitoring thread */
1264static int sh_binary_running;         /* Enable sampling in the thread */
1265
1266static void print_pc_histo(char *core_name, struct sh_css_pc_histogram *hist)
1267{
1268        unsigned int i;
1269        unsigned int cnt_run = 0;
1270        unsigned int cnt_stall = 0;
1271
1272        if (!hist)
1273                return;
1274
1275        sh_css_print("%s histogram length = %d\n", core_name, hist->length);
1276        sh_css_print("%s PC\turn\tstall\n", core_name);
1277
1278        for (i = 0; i < hist->length; i++) {
1279                if ((hist->run[i] == 0) && (hist->run[i] == hist->stall[i]))
1280                        continue;
1281                sh_css_print("%s %d\t%d\t%d\n",
1282                             core_name, i, hist->run[i], hist->stall[i]);
1283                cnt_run += hist->run[i];
1284                cnt_stall += hist->stall[i];
1285        }
1286
1287        sh_css_print(" Statistics for %s, cnt_run = %d, cnt_stall = %d, hist->length = %d\n",
1288                     core_name, cnt_run, cnt_stall, hist->length);
1289}
1290
1291static void print_pc_histogram(void)
1292{
1293        struct ia_css_binary_metrics *metrics;
1294
1295        for (metrics = sh_css_metrics.binary_metrics;
1296             metrics;
1297             metrics = metrics->next) {
1298                if (metrics->mode == IA_CSS_BINARY_MODE_PREVIEW ||
1299                    metrics->mode == IA_CSS_BINARY_MODE_VF_PP) {
1300                        sh_css_print("pc_histogram for binary %d is SKIPPED\n",
1301                                     metrics->id);
1302                        continue;
1303                }
1304
1305                sh_css_print(" pc_histogram for binary %d\n", metrics->id);
1306                print_pc_histo("  ISP", &metrics->isp_histogram);
1307                print_pc_histo("  SP",   &metrics->sp_histogram);
1308                sh_css_print("print_pc_histogram() done for binary->id = %d, done.\n",
1309                             metrics->id);
1310        }
1311
1312        sh_css_print("PC_MONITORING:print_pc_histogram() -- DONE\n");
1313}
1314
1315static int pc_monitoring(void *data)
1316{
1317        int i = 0;
1318
1319        (void)data;
1320        while (true) {
1321                if (sh_binary_running) {
1322                        sh_css_metrics_sample_pcs();
1323#if MULTIPLE_SAMPLES
1324                        for (i = 0; i < NOF_SAMPLES; i++)
1325                                sh_css_metrics_sample_pcs();
1326#endif
1327                }
1328                usleep_range(10, 50);
1329        }
1330        return 0;
1331}
1332
1333static void spying_thread_create(void)
1334{
1335        my_kthread = kthread_run(pc_monitoring, NULL, "sh_pc_monitor");
1336        sh_css_metrics_enable_pc_histogram(1);
1337}
1338
1339static void input_frame_info(struct ia_css_frame_info frame_info)
1340{
1341        sh_css_print("SH_CSS:input_frame_info() -- frame->info.res.width = %d, frame->info.res.height = %d, format = %d\n",
1342                     frame_info.res.width, frame_info.res.height, frame_info.format);
1343}
1344#endif /* WITH_PC_MONITORING */
1345
1346static void
1347start_binary(struct ia_css_pipe *pipe,
1348             struct ia_css_binary *binary)
1349{
1350        assert(pipe);
1351        /* Acceleration uses firmware, the binary thus can be NULL */
1352
1353        if (binary)
1354                sh_css_metrics_start_binary(&binary->metrics);
1355
1356#if WITH_PC_MONITORING
1357        sh_css_print("PC_MONITORING: %s() -- binary id = %d , enable_dvs_envelope = %d\n",
1358                     __func__, binary->info->sp.id,
1359                     binary->info->sp.enable.dvs_envelope);
1360        input_frame_info(binary->in_frame_info);
1361
1362        if (binary && binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_VIDEO)
1363                sh_binary_running = true;
1364#endif
1365
1366#if !defined(ISP2401)
1367        if (pipe->stream->reconfigure_css_rx) {
1368                ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
1369                                         pipe->stream->config.mode);
1370                pipe->stream->reconfigure_css_rx = false;
1371        }
1372#endif
1373}
1374
1375/* start the copy function on the SP */
1376static int
1377start_copy_on_sp(struct ia_css_pipe *pipe,
1378                 struct ia_css_frame *out_frame)
1379{
1380        (void)out_frame;
1381
1382        if ((!pipe) || (!pipe->stream))
1383                return -EINVAL;
1384
1385#if !defined(ISP2401)
1386        if (pipe->stream->reconfigure_css_rx)
1387                ia_css_isys_rx_disable();
1388#endif
1389
1390        if (pipe->stream->config.input_config.format != ATOMISP_INPUT_FORMAT_BINARY_8)
1391                return -EINVAL;
1392        sh_css_sp_start_binary_copy(ia_css_pipe_get_pipe_num(pipe), out_frame, pipe->stream->config.pixels_per_clock == 2);
1393
1394#if !defined(ISP2401)
1395        if (pipe->stream->reconfigure_css_rx) {
1396                ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
1397                                         pipe->stream->config.mode);
1398                pipe->stream->reconfigure_css_rx = false;
1399        }
1400#endif
1401
1402        return 0;
1403}
1404
1405void sh_css_binary_args_reset(struct sh_css_binary_args *args)
1406{
1407        unsigned int i;
1408
1409        for (i = 0; i < NUM_TNR_FRAMES; i++)
1410                args->tnr_frames[i] = NULL;
1411        for (i = 0; i < MAX_NUM_VIDEO_DELAY_FRAMES; i++)
1412                args->delay_frames[i] = NULL;
1413        args->in_frame      = NULL;
1414        for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++)
1415                args->out_frame[i] = NULL;
1416        args->out_vf_frame  = NULL;
1417        args->copy_vf       = false;
1418        args->copy_output   = true;
1419        args->vf_downscale_log2 = 0;
1420}
1421
1422static void start_pipe(
1423    struct ia_css_pipe *me,
1424    enum sh_css_pipe_config_override copy_ovrd,
1425    enum ia_css_input_mode input_mode)
1426{
1427        const struct ia_css_coordinate *coord = NULL;
1428        const struct ia_css_isp_parameters *params = NULL;
1429
1430
1431        IA_CSS_ENTER_PRIVATE("me = %p, copy_ovrd = %d, input_mode = %d",
1432                             me, copy_ovrd, input_mode);
1433
1434        assert(me); /* all callers are in this file and call with non null argument */
1435
1436        if (!IS_ISP2401) {
1437                coord = &me->config.internal_frame_origin_bqs_on_sctbl;
1438                params = me->stream->isp_params_configs;
1439        }
1440
1441        sh_css_sp_init_pipeline(&me->pipeline,
1442                                me->mode,
1443                                (uint8_t)ia_css_pipe_get_pipe_num(me),
1444                                me->config.default_capture_config.enable_xnr != 0,
1445                                me->stream->config.pixels_per_clock == 2,
1446                                me->stream->config.continuous,
1447                                false,
1448                                me->required_bds_factor,
1449                                copy_ovrd,
1450                                input_mode,
1451                                &me->stream->config.metadata_config,
1452                                &me->stream->info.metadata_info
1453                                , (input_mode == IA_CSS_INPUT_MODE_MEMORY) ?
1454                                (enum mipi_port_id)0 :
1455                                me->stream->config.source.port.port,
1456                                coord,
1457                                params);
1458
1459        if (me->config.mode != IA_CSS_PIPE_MODE_COPY) {
1460                struct ia_css_pipeline_stage *stage;
1461
1462                stage = me->pipeline.stages;
1463                if (stage) {
1464                        me->pipeline.current_stage = stage;
1465                        start_binary(me, stage->binary);
1466                }
1467        }
1468        IA_CSS_LEAVE_PRIVATE("void");
1469}
1470
1471void
1472sh_css_invalidate_shading_tables(struct ia_css_stream *stream)
1473{
1474        int i;
1475
1476        assert(stream);
1477
1478        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1479                            "sh_css_invalidate_shading_tables() enter:\n");
1480
1481        for (i = 0; i < stream->num_pipes; i++) {
1482                assert(stream->pipes[i]);
1483                sh_css_pipe_free_shading_table(stream->pipes[i]);
1484        }
1485
1486        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1487                            "sh_css_invalidate_shading_tables() leave: return_void\n");
1488}
1489
1490static void
1491enable_interrupts(enum ia_css_irq_type irq_type)
1492{
1493#ifndef ISP2401
1494        enum mipi_port_id port;
1495#endif
1496        bool enable_pulse = irq_type != IA_CSS_IRQ_TYPE_EDGE;
1497
1498        IA_CSS_ENTER_PRIVATE("");
1499        /* Enable IRQ on the SP which signals that SP goes to idle
1500         * (aka ready state) */
1501        cnd_sp_irq_enable(SP0_ID, true);
1502        /* Set the IRQ device 0 to either level or pulse */
1503        irq_enable_pulse(IRQ0_ID, enable_pulse);
1504
1505        cnd_virq_enable_channel(virq_sp, true);
1506
1507        /* Enable SW interrupt 0, this is used to signal ISYS events */
1508        cnd_virq_enable_channel(
1509            (enum virq_id)(IRQ_SW_CHANNEL0_ID + IRQ_SW_CHANNEL_OFFSET),
1510            true);
1511        /* Enable SW interrupt 1, this is used to signal PSYS events */
1512        cnd_virq_enable_channel(
1513            (enum virq_id)(IRQ_SW_CHANNEL1_ID + IRQ_SW_CHANNEL_OFFSET),
1514            true);
1515
1516#ifndef ISP2401
1517        for (port = 0; port < N_MIPI_PORT_ID; port++)
1518                ia_css_isys_rx_enable_all_interrupts(port);
1519#endif
1520
1521        IA_CSS_LEAVE_PRIVATE("");
1522}
1523
1524static bool sh_css_setup_spctrl_config(const struct ia_css_fw_info *fw,
1525                                       const char *program,
1526                                       ia_css_spctrl_cfg  *spctrl_cfg)
1527{
1528        if ((!fw) || (!spctrl_cfg))
1529                return false;
1530        spctrl_cfg->sp_entry = 0;
1531        spctrl_cfg->program_name = (char *)(program);
1532
1533        spctrl_cfg->ddr_data_offset =  fw->blob.data_source;
1534        spctrl_cfg->dmem_data_addr = fw->blob.data_target;
1535        spctrl_cfg->dmem_bss_addr = fw->blob.bss_target;
1536        spctrl_cfg->data_size = fw->blob.data_size;
1537        spctrl_cfg->bss_size = fw->blob.bss_size;
1538
1539        spctrl_cfg->spctrl_config_dmem_addr = fw->info.sp.init_dmem_data;
1540        spctrl_cfg->spctrl_state_dmem_addr = fw->info.sp.sw_state;
1541
1542        spctrl_cfg->code_size = fw->blob.size;
1543        spctrl_cfg->code      = fw->blob.code;
1544        spctrl_cfg->sp_entry  = fw->info.sp.sp_entry; /* entry function ptr on SP */
1545
1546        return true;
1547}
1548
1549void
1550ia_css_unload_firmware(void)
1551{
1552        if (sh_css_num_binaries) {
1553                /* we have already loaded before so get rid of the old stuff */
1554                ia_css_binary_uninit();
1555                sh_css_unload_firmware();
1556        }
1557        fw_explicitly_loaded = false;
1558}
1559
1560static void
1561ia_css_reset_defaults(struct sh_css *css)
1562{
1563        struct sh_css default_css;
1564
1565        /* Reset everything to zero */
1566        memset(&default_css, 0, sizeof(default_css));
1567
1568        /* Initialize the non zero values*/
1569        default_css.check_system_idle = true;
1570        default_css.num_cont_raw_frames = NUM_CONTINUOUS_FRAMES;
1571
1572        /* All should be 0: but memset does it already.
1573         * default_css.num_mipi_frames[N_CSI_PORTS] = 0;
1574         */
1575
1576        default_css.irq_type = IA_CSS_IRQ_TYPE_EDGE;
1577
1578        /*Set the defaults to the output */
1579        *css = default_css;
1580}
1581
1582int
1583ia_css_load_firmware(struct device *dev, const struct ia_css_env *env,
1584                     const struct ia_css_fw  *fw)
1585{
1586        int err;
1587
1588        if (!env)
1589                return -EINVAL;
1590        if (!fw)
1591                return -EINVAL;
1592
1593        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() enter\n");
1594
1595        /* make sure we initialize my_css */
1596        if (my_css.flush != env->cpu_mem_env.flush) {
1597                ia_css_reset_defaults(&my_css);
1598                my_css.flush = env->cpu_mem_env.flush;
1599        }
1600
1601        ia_css_unload_firmware(); /* in case we are called twice */
1602        err = sh_css_load_firmware(dev, fw->data, fw->bytes);
1603        if (!err) {
1604                err = ia_css_binary_init_infos();
1605                if (!err)
1606                        fw_explicitly_loaded = true;
1607        }
1608
1609        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() leave\n");
1610        return err;
1611}
1612
1613int
1614ia_css_init(struct device *dev, const struct ia_css_env *env,
1615            const struct ia_css_fw  *fw,
1616            u32                 mmu_l1_base,
1617            enum ia_css_irq_type     irq_type)
1618{
1619        int err;
1620        ia_css_spctrl_cfg spctrl_cfg;
1621
1622        void (*flush_func)(struct ia_css_acc_fw *fw);
1623        hrt_data select, enable;
1624
1625        /*
1626         * The C99 standard does not specify the exact object representation of structs;
1627         * the representation is compiler dependent.
1628         *
1629         * The structs that are communicated between host and SP/ISP should have the
1630         * exact same object representation. The compiler that is used to compile the
1631         * firmware is hivecc.
1632         *
1633         * To check if a different compiler, used to compile a host application, uses
1634         * another object representation, macros are defined specifying the size of
1635         * the structs as expected by the firmware.
1636         *
1637         * A host application shall verify that a sizeof( ) of the struct is equal to
1638         * the SIZE_OF_XXX macro of the corresponding struct. If they are not
1639         * equal, functionality will break.
1640         */
1641        /* Check struct sh_css_ddr_address_map */
1642        COMPILATION_ERROR_IF(sizeof(struct sh_css_ddr_address_map)              != SIZE_OF_SH_CSS_DDR_ADDRESS_MAP_STRUCT);
1643        /* Check struct host_sp_queues */
1644        COMPILATION_ERROR_IF(sizeof(struct host_sp_queues)                      != SIZE_OF_HOST_SP_QUEUES_STRUCT);
1645        COMPILATION_ERROR_IF(sizeof(struct ia_css_circbuf_desc_s)               != SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT);
1646        COMPILATION_ERROR_IF(sizeof(struct ia_css_circbuf_elem_s)               != SIZE_OF_IA_CSS_CIRCBUF_ELEM_S_STRUCT);
1647
1648        /* Check struct host_sp_communication */
1649        COMPILATION_ERROR_IF(sizeof(struct host_sp_communication)               != SIZE_OF_HOST_SP_COMMUNICATION_STRUCT);
1650        COMPILATION_ERROR_IF(sizeof(struct sh_css_event_irq_mask)               != SIZE_OF_SH_CSS_EVENT_IRQ_MASK_STRUCT);
1651
1652        /* Check struct sh_css_hmm_buffer */
1653        COMPILATION_ERROR_IF(sizeof(struct sh_css_hmm_buffer)                   != SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT);
1654        COMPILATION_ERROR_IF(sizeof(struct ia_css_isp_3a_statistics)            != SIZE_OF_IA_CSS_ISP_3A_STATISTICS_STRUCT);
1655        COMPILATION_ERROR_IF(sizeof(struct ia_css_isp_dvs_statistics)           != SIZE_OF_IA_CSS_ISP_DVS_STATISTICS_STRUCT);
1656        COMPILATION_ERROR_IF(sizeof(struct ia_css_metadata)                     != SIZE_OF_IA_CSS_METADATA_STRUCT);
1657
1658        /* Check struct ia_css_init_dmem_cfg */
1659        COMPILATION_ERROR_IF(sizeof(struct ia_css_sp_init_dmem_cfg)             != SIZE_OF_IA_CSS_SP_INIT_DMEM_CFG_STRUCT);
1660
1661        if (!fw && !fw_explicitly_loaded)
1662                return -EINVAL;
1663        if (!env)
1664                return -EINVAL;
1665
1666        sh_css_printf = env->print_env.debug_print;
1667
1668        IA_CSS_ENTER("void");
1669
1670        flush_func     = env->cpu_mem_env.flush;
1671
1672        pipe_global_init();
1673        ia_css_pipeline_init();
1674        ia_css_queue_map_init();
1675
1676        ia_css_device_access_init(&env->hw_access_env);
1677
1678        select = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_select)
1679        & (~GPIO_FLASH_PIN_MASK);
1680        enable = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_e)
1681        | GPIO_FLASH_PIN_MASK;
1682        sh_css_mmu_set_page_table_base_index(mmu_l1_base);
1683
1684        my_css_save.mmu_base = mmu_l1_base;
1685
1686        ia_css_reset_defaults(&my_css);
1687
1688        my_css_save.driver_env = *env;
1689        my_css.flush     = flush_func;
1690
1691        err = ia_css_rmgr_init();
1692        if (err) {
1693                IA_CSS_LEAVE_ERR(err);
1694                return err;
1695        }
1696
1697        IA_CSS_LOG("init: %d", my_css_save_initialized);
1698
1699        if (!my_css_save_initialized) {
1700                my_css_save_initialized = true;
1701                my_css_save.mode = sh_css_mode_working;
1702                memset(my_css_save.stream_seeds, 0,
1703                       sizeof(struct sh_css_stream_seed) * MAX_ACTIVE_STREAMS);
1704                IA_CSS_LOG("init: %d mode=%d", my_css_save_initialized, my_css_save.mode);
1705        }
1706
1707        mipi_init();
1708
1709#ifndef ISP2401
1710        /* In case this has been programmed already, update internal
1711           data structure ... DEPRECATED */
1712        my_css.page_table_base_index = mmu_get_page_table_base_index(MMU0_ID);
1713
1714#endif
1715        my_css.irq_type = irq_type;
1716
1717        my_css_save.irq_type = irq_type;
1718
1719        enable_interrupts(my_css.irq_type);
1720
1721        /* configure GPIO to output mode */
1722        gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_select, select);
1723        gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_e, enable);
1724        gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_0, 0);
1725
1726        err = ia_css_refcount_init(REFCOUNT_SIZE);
1727        if (err) {
1728                IA_CSS_LEAVE_ERR(err);
1729                return err;
1730        }
1731        err = sh_css_params_init();
1732        if (err) {
1733                IA_CSS_LEAVE_ERR(err);
1734                return err;
1735        }
1736        if (fw) {
1737                ia_css_unload_firmware(); /* in case we already had firmware loaded */
1738                err = sh_css_load_firmware(dev, fw->data, fw->bytes);
1739                if (err) {
1740                        IA_CSS_LEAVE_ERR(err);
1741                        return err;
1742                }
1743                err = ia_css_binary_init_infos();
1744                if (err) {
1745                        IA_CSS_LEAVE_ERR(err);
1746                        return err;
1747                }
1748                fw_explicitly_loaded = false;
1749#ifndef ISP2401
1750                my_css_save.loaded_fw = (struct ia_css_fw *)fw;
1751#endif
1752        }
1753        if (!sh_css_setup_spctrl_config(&sh_css_sp_fw, SP_PROG_NAME, &spctrl_cfg))
1754                return -EINVAL;
1755
1756        err = ia_css_spctrl_load_fw(SP0_ID, &spctrl_cfg);
1757        if (err) {
1758                IA_CSS_LEAVE_ERR(err);
1759                return err;
1760        }
1761
1762#if WITH_PC_MONITORING
1763        if (!thread_alive) {
1764                thread_alive++;
1765                sh_css_print("PC_MONITORING: %s() -- create thread DISABLED\n",
1766                             __func__);
1767                spying_thread_create();
1768        }
1769#endif
1770        if (!sh_css_hrt_system_is_idle()) {
1771                IA_CSS_LEAVE_ERR(-EBUSY);
1772                return -EBUSY;
1773        }
1774        /* can be called here, queuing works, but:
1775           - when sp is started later, it will wipe queued items
1776           so for now we leave it for later and make sure
1777           updates are not called to frequently.
1778        sh_css_init_buffer_queues();
1779        */
1780
1781#if defined(ISP2401)
1782        gp_device_reg_store(GP_DEVICE0_ID, _REG_GP_SWITCH_ISYS2401_ADDR, 1);
1783#endif
1784
1785
1786        if (!IS_ISP2401)
1787                dma_set_max_burst_size(DMA0_ID, HIVE_DMA_BUS_DDR_CONN,
1788                                       ISP2400_DMA_MAX_BURST_LENGTH);
1789        else
1790                dma_set_max_burst_size(DMA0_ID, HIVE_DMA_BUS_DDR_CONN,
1791                                       ISP2401_DMA_MAX_BURST_LENGTH);
1792
1793        if (ia_css_isys_init() != INPUT_SYSTEM_ERR_NO_ERROR)
1794                err = -EINVAL;
1795
1796        sh_css_params_map_and_store_default_gdc_lut();
1797
1798        IA_CSS_LEAVE_ERR(err);
1799        return err;
1800}
1801
1802int
1803ia_css_enable_isys_event_queue(bool enable)
1804{
1805        if (sh_css_sp_is_running())
1806                return -EBUSY;
1807        sh_css_sp_enable_isys_event_queue(enable);
1808        return 0;
1809}
1810
1811/* For Acceleration API: Flush FW (shared buffer pointer) arguments */
1812void
1813sh_css_flush(struct ia_css_acc_fw *fw)
1814{
1815        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "sh_css_flush() enter:\n");
1816        if ((fw) && (my_css.flush))
1817                my_css.flush(fw);
1818}
1819
1820/* Mapping sp threads. Currently, this is done when a stream is created and
1821 * pipelines are ready to be converted to sp pipelines. Be careful if you are
1822 * doing it from stream_create since we could run out of sp threads due to
1823 * allocation on inactive pipelines. */
1824static int
1825map_sp_threads(struct ia_css_stream *stream, bool map)
1826{
1827        struct ia_css_pipe *main_pipe = NULL;
1828        struct ia_css_pipe *copy_pipe = NULL;
1829        struct ia_css_pipe *capture_pipe = NULL;
1830        struct ia_css_pipe *acc_pipe = NULL;
1831        int err = 0;
1832        enum ia_css_pipe_id pipe_id;
1833
1834        IA_CSS_ENTER_PRIVATE("stream = %p, map = %s",
1835                             stream, map ? "true" : "false");
1836
1837        if (!stream) {
1838                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
1839                return -EINVAL;
1840        }
1841
1842        main_pipe = stream->last_pipe;
1843        pipe_id = main_pipe->mode;
1844
1845        ia_css_pipeline_map(main_pipe->pipe_num, map);
1846
1847        switch (pipe_id) {
1848        case IA_CSS_PIPE_ID_PREVIEW:
1849                copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
1850                capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
1851                acc_pipe     = main_pipe->pipe_settings.preview.acc_pipe;
1852                break;
1853
1854        case IA_CSS_PIPE_ID_VIDEO:
1855                copy_pipe    = main_pipe->pipe_settings.video.copy_pipe;
1856                capture_pipe = main_pipe->pipe_settings.video.capture_pipe;
1857                break;
1858
1859        case IA_CSS_PIPE_ID_CAPTURE:
1860        case IA_CSS_PIPE_ID_ACC:
1861        default:
1862                break;
1863        }
1864
1865        if (acc_pipe)
1866                ia_css_pipeline_map(acc_pipe->pipe_num, map);
1867
1868        if (capture_pipe)
1869                ia_css_pipeline_map(capture_pipe->pipe_num, map);
1870
1871        /* Firmware expects copy pipe to be the last pipe mapped. (if needed) */
1872        if (copy_pipe)
1873                ia_css_pipeline_map(copy_pipe->pipe_num, map);
1874
1875        /* DH regular multi pipe - not continuous mode: map the next pipes too */
1876        if (!stream->config.continuous) {
1877                int i;
1878
1879                for (i = 1; i < stream->num_pipes; i++)
1880                        ia_css_pipeline_map(stream->pipes[i]->pipe_num, map);
1881        }
1882
1883        IA_CSS_LEAVE_ERR_PRIVATE(err);
1884        return err;
1885}
1886
1887/* creates a host pipeline skeleton for all pipes in a stream. Called during
1888 * stream_create. */
1889static int
1890create_host_pipeline_structure(struct ia_css_stream *stream)
1891{
1892        struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
1893        struct ia_css_pipe *acc_pipe = NULL;
1894        enum ia_css_pipe_id pipe_id;
1895        struct ia_css_pipe *main_pipe = NULL;
1896        int err = 0;
1897        unsigned int copy_pipe_delay = 0,
1898        capture_pipe_delay = 0;
1899
1900        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
1901
1902        if (!stream) {
1903                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
1904                return -EINVAL;
1905        }
1906
1907        main_pipe       = stream->last_pipe;
1908        if (!main_pipe) {
1909                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
1910                return -EINVAL;
1911        }
1912
1913        pipe_id = main_pipe->mode;
1914
1915        switch (pipe_id) {
1916        case IA_CSS_PIPE_ID_PREVIEW:
1917                copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
1918                copy_pipe_delay = main_pipe->dvs_frame_delay;
1919                capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
1920                capture_pipe_delay = IA_CSS_FRAME_DELAY_0;
1921                acc_pipe     = main_pipe->pipe_settings.preview.acc_pipe;
1922                err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1923                                             main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1924                break;
1925
1926        case IA_CSS_PIPE_ID_VIDEO:
1927                copy_pipe    = main_pipe->pipe_settings.video.copy_pipe;
1928                copy_pipe_delay = main_pipe->dvs_frame_delay;
1929                capture_pipe = main_pipe->pipe_settings.video.capture_pipe;
1930                capture_pipe_delay = IA_CSS_FRAME_DELAY_0;
1931                err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1932                                             main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1933                break;
1934
1935        case IA_CSS_PIPE_ID_CAPTURE:
1936                capture_pipe = main_pipe;
1937                capture_pipe_delay = main_pipe->dvs_frame_delay;
1938                break;
1939
1940        case IA_CSS_PIPE_ID_YUVPP:
1941                err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1942                                             main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1943                break;
1944
1945        case IA_CSS_PIPE_ID_ACC:
1946                err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1947                                             main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1948                break;
1949
1950        default:
1951                err = -EINVAL;
1952        }
1953
1954        if (!(err) && copy_pipe)
1955                err = ia_css_pipeline_create(&copy_pipe->pipeline,
1956                                             copy_pipe->mode,
1957                                             copy_pipe->pipe_num,
1958                                             copy_pipe_delay);
1959
1960        if (!(err) && capture_pipe)
1961                err = ia_css_pipeline_create(&capture_pipe->pipeline,
1962                                             capture_pipe->mode,
1963                                             capture_pipe->pipe_num,
1964                                             capture_pipe_delay);
1965
1966        if (!(err) && acc_pipe)
1967                err = ia_css_pipeline_create(&acc_pipe->pipeline, acc_pipe->mode,
1968                                             acc_pipe->pipe_num, main_pipe->dvs_frame_delay);
1969
1970        /* DH regular multi pipe - not continuous mode: create the next pipelines too */
1971        if (!stream->config.continuous) {
1972                int i;
1973
1974                for (i = 1; i < stream->num_pipes && 0 == err; i++) {
1975                        main_pipe = stream->pipes[i];
1976                        err = ia_css_pipeline_create(&main_pipe->pipeline,
1977                                                     main_pipe->mode,
1978                                                     main_pipe->pipe_num,
1979                                                     main_pipe->dvs_frame_delay);
1980                }
1981        }
1982
1983        IA_CSS_LEAVE_ERR_PRIVATE(err);
1984        return err;
1985}
1986
1987/* creates a host pipeline for all pipes in a stream. Called during
1988 * stream_start. */
1989static int
1990create_host_pipeline(struct ia_css_stream *stream)
1991{
1992        struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
1993        struct ia_css_pipe *acc_pipe = NULL;
1994        enum ia_css_pipe_id pipe_id;
1995        struct ia_css_pipe *main_pipe = NULL;
1996        int err = 0;
1997        unsigned int max_input_width = 0;
1998
1999        IA_CSS_ENTER_PRIVATE("stream = %p", stream);
2000        if (!stream) {
2001                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2002                return -EINVAL;
2003        }
2004
2005        main_pipe       = stream->last_pipe;
2006        pipe_id = main_pipe->mode;
2007
2008        /* No continuous frame allocation for capture pipe. It uses the
2009         * "main" pipe's frames. */
2010        if ((pipe_id == IA_CSS_PIPE_ID_PREVIEW) ||
2011            (pipe_id == IA_CSS_PIPE_ID_VIDEO)) {
2012                /* About pipe_id == IA_CSS_PIPE_ID_PREVIEW && stream->config.mode != IA_CSS_INPUT_MODE_MEMORY:
2013                 * The original condition pipe_id == IA_CSS_PIPE_ID_PREVIEW is too strong. E.g. in SkyCam (with memory
2014                 * based input frames) there is no continuous mode and thus no need for allocated continuous frames
2015                 * This is not only for SkyCam but for all preview cases that use DDR based input frames. For this
2016                 * reason the stream->config.mode != IA_CSS_INPUT_MODE_MEMORY has beed added.
2017                 */
2018                if (stream->config.continuous ||
2019                    (pipe_id == IA_CSS_PIPE_ID_PREVIEW &&
2020                     stream->config.mode != IA_CSS_INPUT_MODE_MEMORY)) {
2021                        err = alloc_continuous_frames(main_pipe, true);
2022                        if (err)
2023                                goto ERR;
2024                }
2025        }
2026
2027#if !defined(ISP2401)
2028        /* old isys: need to allocate_mipi_frames() even in IA_CSS_PIPE_MODE_COPY */
2029        if (pipe_id != IA_CSS_PIPE_ID_ACC) {
2030                err = allocate_mipi_frames(main_pipe, &stream->info);
2031                if (err)
2032                        goto ERR;
2033        }
2034#elif defined(ISP2401)
2035        if ((pipe_id != IA_CSS_PIPE_ID_ACC) &&
2036            (main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
2037                err = allocate_mipi_frames(main_pipe, &stream->info);
2038                if (err)
2039                        goto ERR;
2040        }
2041#endif
2042
2043        switch (pipe_id) {
2044        case IA_CSS_PIPE_ID_PREVIEW:
2045                copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
2046                capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
2047                acc_pipe     = main_pipe->pipe_settings.preview.acc_pipe;
2048                max_input_width =
2049                    main_pipe->pipe_settings.preview.preview_binary.info->sp.input.max_width;
2050
2051                err = create_host_preview_pipeline(main_pipe);
2052                if (err)
2053                        goto ERR;
2054
2055                break;
2056
2057        case IA_CSS_PIPE_ID_VIDEO:
2058                copy_pipe    = main_pipe->pipe_settings.video.copy_pipe;
2059                capture_pipe = main_pipe->pipe_settings.video.capture_pipe;
2060                max_input_width =
2061                    main_pipe->pipe_settings.video.video_binary.info->sp.input.max_width;
2062
2063                err = create_host_video_pipeline(main_pipe);
2064                if (err)
2065                        goto ERR;
2066
2067                break;
2068
2069        case IA_CSS_PIPE_ID_CAPTURE:
2070                capture_pipe = main_pipe;
2071
2072                break;
2073
2074        case IA_CSS_PIPE_ID_YUVPP:
2075                err = create_host_yuvpp_pipeline(main_pipe);
2076                if (err)
2077                        goto ERR;
2078
2079                break;
2080
2081        case IA_CSS_PIPE_ID_ACC:
2082                err = create_host_acc_pipeline(main_pipe);
2083                if (err)
2084                        goto ERR;
2085
2086                break;
2087        default:
2088                err = -EINVAL;
2089        }
2090        if (err)
2091                goto ERR;
2092
2093        if (copy_pipe) {
2094                err = create_host_copy_pipeline(copy_pipe, max_input_width,
2095                                                main_pipe->continuous_frames[0]);
2096                if (err)
2097                        goto ERR;
2098        }
2099
2100        if (capture_pipe) {
2101                err = create_host_capture_pipeline(capture_pipe);
2102                if (err)
2103                        goto ERR;
2104        }
2105
2106        if (acc_pipe) {
2107                err = create_host_acc_pipeline(acc_pipe);
2108                if (err)
2109                        goto ERR;
2110        }
2111
2112        /* DH regular multi pipe - not continuous mode: create the next pipelines too */
2113        if (!stream->config.continuous) {
2114                int i;
2115
2116                for (i = 1; i < stream->num_pipes && 0 == err; i++) {
2117                        switch (stream->pipes[i]->mode) {
2118                        case IA_CSS_PIPE_ID_PREVIEW:
2119                                err = create_host_preview_pipeline(stream->pipes[i]);
2120                                break;
2121                        case IA_CSS_PIPE_ID_VIDEO:
2122                                err = create_host_video_pipeline(stream->pipes[i]);
2123                                break;
2124                        case IA_CSS_PIPE_ID_CAPTURE:
2125                                err = create_host_capture_pipeline(stream->pipes[i]);
2126                                break;
2127                        case IA_CSS_PIPE_ID_YUVPP:
2128                                err = create_host_yuvpp_pipeline(stream->pipes[i]);
2129                                break;
2130                        case IA_CSS_PIPE_ID_ACC:
2131                                err = create_host_acc_pipeline(stream->pipes[i]);
2132                                break;
2133                        default:
2134                                err = -EINVAL;
2135                        }
2136                        if (err)
2137                                goto ERR;
2138                }
2139        }
2140
2141ERR:
2142        IA_CSS_LEAVE_ERR_PRIVATE(err);
2143        return err;
2144}
2145
2146static const struct ia_css_pipe default_pipe = IA_CSS_DEFAULT_PIPE;
2147static const struct ia_css_preview_settings preview = IA_CSS_DEFAULT_PREVIEW_SETTINGS;
2148static const struct ia_css_capture_settings capture = IA_CSS_DEFAULT_CAPTURE_SETTINGS;
2149static const struct ia_css_video_settings video = IA_CSS_DEFAULT_VIDEO_SETTINGS;
2150static const struct ia_css_yuvpp_settings yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS;
2151
2152static int
2153init_pipe_defaults(enum ia_css_pipe_mode mode,
2154                   struct ia_css_pipe *pipe,
2155                   bool copy_pipe)
2156{
2157        if (!pipe) {
2158                IA_CSS_ERROR("NULL pipe parameter");
2159                return -EINVAL;
2160        }
2161
2162        /* Initialize pipe to pre-defined defaults */
2163        memcpy(pipe, &default_pipe, sizeof(default_pipe));
2164
2165        /* TODO: JB should not be needed, but temporary backward reference */
2166        switch (mode) {
2167        case IA_CSS_PIPE_MODE_PREVIEW:
2168                pipe->mode = IA_CSS_PIPE_ID_PREVIEW;
2169                memcpy(&pipe->pipe_settings.preview, &preview, sizeof(preview));
2170                break;
2171        case IA_CSS_PIPE_MODE_CAPTURE:
2172                if (copy_pipe)
2173                        pipe->mode = IA_CSS_PIPE_ID_COPY;
2174                else
2175                        pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
2176
2177                memcpy(&pipe->pipe_settings.capture, &capture, sizeof(capture));
2178                break;
2179        case IA_CSS_PIPE_MODE_VIDEO:
2180                pipe->mode = IA_CSS_PIPE_ID_VIDEO;
2181                memcpy(&pipe->pipe_settings.video, &video, sizeof(video));
2182                break;
2183        case IA_CSS_PIPE_MODE_ACC:
2184                pipe->mode = IA_CSS_PIPE_ID_ACC;
2185                break;
2186        case IA_CSS_PIPE_MODE_COPY:
2187                pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
2188                break;
2189        case IA_CSS_PIPE_MODE_YUVPP:
2190                pipe->mode = IA_CSS_PIPE_ID_YUVPP;
2191                memcpy(&pipe->pipe_settings.yuvpp, &yuvpp, sizeof(yuvpp));
2192                break;
2193        default:
2194                return -EINVAL;
2195        }
2196
2197        return 0;
2198}
2199
2200static void
2201pipe_global_init(void)
2202{
2203        u8 i;
2204
2205        my_css.pipe_counter = 0;
2206        for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++)
2207                my_css.all_pipes[i] = NULL;
2208}
2209
2210static int
2211pipe_generate_pipe_num(const struct ia_css_pipe *pipe,
2212                       unsigned int *pipe_number)
2213{
2214        const u8 INVALID_PIPE_NUM = (uint8_t)~(0);
2215        u8 pipe_num = INVALID_PIPE_NUM;
2216        u8 i;
2217
2218        if (!pipe) {
2219                IA_CSS_ERROR("NULL pipe parameter");
2220                return -EINVAL;
2221        }
2222
2223        /* Assign a new pipe_num .... search for empty place */
2224        for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
2225                if (!my_css.all_pipes[i]) {
2226                        /*position is reserved */
2227                        my_css.all_pipes[i] = (struct ia_css_pipe *)pipe;
2228                        pipe_num = i;
2229                        break;
2230                }
2231        }
2232        if (pipe_num == INVALID_PIPE_NUM) {
2233                /* Max number of pipes already allocated */
2234                IA_CSS_ERROR("Max number of pipes already created");
2235                return -ENOSPC;
2236        }
2237
2238        my_css.pipe_counter++;
2239
2240        IA_CSS_LOG("pipe_num (%d)", pipe_num);
2241
2242        *pipe_number = pipe_num;
2243        return 0;
2244}
2245
2246static void
2247pipe_release_pipe_num(unsigned int pipe_num)
2248{
2249        my_css.all_pipes[pipe_num] = NULL;
2250        my_css.pipe_counter--;
2251        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2252                            "pipe_release_pipe_num (%d)\n", pipe_num);
2253}
2254
2255static int
2256create_pipe(enum ia_css_pipe_mode mode,
2257            struct ia_css_pipe **pipe,
2258            bool copy_pipe)
2259{
2260        int err = 0;
2261        struct ia_css_pipe *me;
2262
2263        if (!pipe) {
2264                IA_CSS_ERROR("NULL pipe parameter");
2265                return -EINVAL;
2266        }
2267
2268        me = kmalloc(sizeof(*me), GFP_KERNEL);
2269        if (!me)
2270                return -ENOMEM;
2271
2272        err = init_pipe_defaults(mode, me, copy_pipe);
2273        if (err) {
2274                kfree(me);
2275                return err;
2276        }
2277
2278        err = pipe_generate_pipe_num(me, &me->pipe_num);
2279        if (err) {
2280                kfree(me);
2281                return err;
2282        }
2283
2284        *pipe = me;
2285        return 0;
2286}
2287
2288struct ia_css_pipe *
2289find_pipe_by_num(uint32_t pipe_num)
2290{
2291        unsigned int i;
2292
2293        for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
2294                if (my_css.all_pipes[i] &&
2295                    ia_css_pipe_get_pipe_num(my_css.all_pipes[i]) == pipe_num) {
2296                        return my_css.all_pipes[i];
2297                }
2298        }
2299        return NULL;
2300}
2301
2302static void sh_css_pipe_free_acc_binaries(
2303    struct ia_css_pipe *pipe)
2304{
2305        struct ia_css_pipeline *pipeline;
2306        struct ia_css_pipeline_stage *stage;
2307
2308        if (!pipe) {
2309                IA_CSS_ERROR("NULL input pointer");
2310                return;
2311        }
2312        pipeline = &pipe->pipeline;
2313
2314        /* loop through the stages and unload them */
2315        for (stage = pipeline->stages; stage; stage = stage->next) {
2316                struct ia_css_fw_info *firmware = (struct ia_css_fw_info *)
2317                                                  stage->firmware;
2318                if (firmware)
2319                        ia_css_pipe_unload_extension(pipe, firmware);
2320        }
2321}
2322
2323int
2324ia_css_pipe_destroy(struct ia_css_pipe *pipe)
2325{
2326        int err = 0;
2327
2328        IA_CSS_ENTER("pipe = %p", pipe);
2329
2330        if (!pipe) {
2331                IA_CSS_LEAVE_ERR(-EINVAL);
2332                return -EINVAL;
2333        }
2334
2335        if (pipe->stream) {
2336                IA_CSS_LOG("ia_css_stream_destroy not called!");
2337                IA_CSS_LEAVE_ERR(-EINVAL);
2338                return -EINVAL;
2339        }
2340
2341        switch (pipe->config.mode) {
2342        case IA_CSS_PIPE_MODE_PREVIEW:
2343                /* need to take into account that this function is also called
2344                   on the internal copy pipe */
2345                if (pipe->mode == IA_CSS_PIPE_ID_PREVIEW) {
2346                        ia_css_frame_free_multiple(NUM_CONTINUOUS_FRAMES,
2347                                                   pipe->continuous_frames);
2348                        ia_css_metadata_free_multiple(NUM_CONTINUOUS_FRAMES,
2349                                                      pipe->cont_md_buffers);
2350                        if (pipe->pipe_settings.preview.copy_pipe) {
2351                                err = ia_css_pipe_destroy(pipe->pipe_settings.preview.copy_pipe);
2352                                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2353                                                    "ia_css_pipe_destroy(): destroyed internal copy pipe err=%d\n",
2354                                                    err);
2355                        }
2356                }
2357                break;
2358        case IA_CSS_PIPE_MODE_VIDEO:
2359                if (pipe->mode == IA_CSS_PIPE_ID_VIDEO) {
2360                        ia_css_frame_free_multiple(NUM_CONTINUOUS_FRAMES,
2361                                                   pipe->continuous_frames);
2362                        ia_css_metadata_free_multiple(NUM_CONTINUOUS_FRAMES,
2363                                                      pipe->cont_md_buffers);
2364                        if (pipe->pipe_settings.video.copy_pipe) {
2365                                err = ia_css_pipe_destroy(pipe->pipe_settings.video.copy_pipe);
2366                                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2367                                                    "ia_css_pipe_destroy(): destroyed internal copy pipe err=%d\n",
2368                                                    err);
2369                        }
2370                }
2371#ifndef ISP2401
2372                ia_css_frame_free_multiple(NUM_TNR_FRAMES,
2373                                           pipe->pipe_settings.video.tnr_frames);
2374#else
2375                ia_css_frame_free_multiple(NUM_TNR_FRAMES,
2376                                           pipe->pipe_settings.video.tnr_frames);
2377#endif
2378                ia_css_frame_free_multiple(MAX_NUM_VIDEO_DELAY_FRAMES,
2379                                           pipe->pipe_settings.video.delay_frames);
2380                break;
2381        case IA_CSS_PIPE_MODE_CAPTURE:
2382                ia_css_frame_free_multiple(MAX_NUM_VIDEO_DELAY_FRAMES,
2383                                           pipe->pipe_settings.capture.delay_frames);
2384                break;
2385        case IA_CSS_PIPE_MODE_ACC:
2386                sh_css_pipe_free_acc_binaries(pipe);
2387                break;
2388        case IA_CSS_PIPE_MODE_COPY:
2389                break;
2390        case IA_CSS_PIPE_MODE_YUVPP:
2391                break;
2392        }
2393
2394        sh_css_params_free_gdc_lut(pipe->scaler_pp_lut);
2395        pipe->scaler_pp_lut = mmgr_NULL;
2396
2397        my_css.active_pipes[ia_css_pipe_get_pipe_num(pipe)] = NULL;
2398        sh_css_pipe_free_shading_table(pipe);
2399
2400        ia_css_pipeline_destroy(&pipe->pipeline);
2401        pipe_release_pipe_num(ia_css_pipe_get_pipe_num(pipe));
2402
2403        /* Temporarily, not every sh_css_pipe has an acc_extension. */
2404        if (pipe->config.acc_extension)
2405                ia_css_pipe_unload_extension(pipe, pipe->config.acc_extension);
2406
2407        kfree(pipe);
2408        IA_CSS_LEAVE("err = %d", err);
2409        return err;
2410}
2411
2412void
2413ia_css_uninit(void)
2414{
2415        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_uninit() enter: void\n");
2416#if WITH_PC_MONITORING
2417        sh_css_print("PC_MONITORING: %s() -- started\n", __func__);
2418        print_pc_histogram();
2419#endif
2420
2421        sh_css_params_free_default_gdc_lut();
2422
2423        /* TODO: JB: implement decent check and handling of freeing mipi frames */
2424        //assert(ref_count_mipi_allocation == 0); //mipi frames are not freed
2425        /* cleanup generic data */
2426        sh_css_params_uninit();
2427        ia_css_refcount_uninit();
2428
2429        ia_css_rmgr_uninit();
2430
2431#if !defined(ISP2401)
2432        /* needed for reprogramming the inputformatter after power cycle of css */
2433        ifmtr_set_if_blocking_mode_reset = true;
2434#endif
2435
2436        if (!fw_explicitly_loaded)
2437                ia_css_unload_firmware();
2438
2439        ia_css_spctrl_unload_fw(SP0_ID);
2440        sh_css_sp_set_sp_running(false);
2441        /* check and free any remaining mipi frames */
2442        free_mipi_frames(NULL);
2443
2444        sh_css_sp_reset_global_vars();
2445
2446        ia_css_isys_uninit();
2447
2448        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_uninit() leave: return_void\n");
2449}
2450
2451int ia_css_irq_translate(
2452    unsigned int *irq_infos)
2453{
2454        enum virq_id    irq;
2455        enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_more_irqs;
2456        unsigned int infos = 0;
2457
2458        /* irq_infos can be NULL, but that would make the function useless */
2459        /* assert(irq_infos != NULL); */
2460        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2461                            "ia_css_irq_translate() enter: irq_infos=%p\n", irq_infos);
2462
2463        while (status == hrt_isp_css_irq_status_more_irqs) {
2464                status = virq_get_channel_id(&irq);
2465                if (status == hrt_isp_css_irq_status_error)
2466                        return -EINVAL;
2467
2468#if WITH_PC_MONITORING
2469                sh_css_print("PC_MONITORING: %s() irq = %d, sh_binary_running set to 0\n",
2470                             __func__, irq);
2471                sh_binary_running = 0;
2472#endif
2473
2474                switch (irq) {
2475                case virq_sp:
2476                        /* When SP goes to idle, info is available in the
2477                         * event queue. */
2478                        infos |= IA_CSS_IRQ_INFO_EVENTS_READY;
2479                        break;
2480                case virq_isp:
2481                        break;
2482                case virq_isys_sof:
2483                        infos |= IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF;
2484                        break;
2485                case virq_isys_eof:
2486                        infos |= IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF;
2487                        break;
2488                case virq_isys_csi:
2489                        infos |= IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR;
2490                        break;
2491#if !defined(ISP2401)
2492                case virq_ifmt0_id:
2493                        infos |= IA_CSS_IRQ_INFO_IF_ERROR;
2494                        break;
2495#endif
2496                case virq_dma:
2497                        infos |= IA_CSS_IRQ_INFO_DMA_ERROR;
2498                        break;
2499                case virq_sw_pin_0:
2500                        infos |= sh_css_get_sw_interrupt_value(0);
2501                        break;
2502                case virq_sw_pin_1:
2503                        infos |= sh_css_get_sw_interrupt_value(1);
2504                        /* pqiao TODO: also assumption here */
2505                        break;
2506                default:
2507                        break;
2508                }
2509        }
2510
2511        if (irq_infos)
2512                *irq_infos = infos;
2513
2514        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2515                            "ia_css_irq_translate() leave: irq_infos=%u\n",
2516                            infos);
2517
2518        return 0;
2519}
2520
2521int ia_css_irq_enable(
2522    enum ia_css_irq_info info,
2523    bool enable)
2524{
2525        enum virq_id    irq = N_virq_id;
2526
2527        IA_CSS_ENTER("info=%d, enable=%d", info, enable);
2528
2529        switch (info) {
2530#if !defined(ISP2401)
2531        case IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF:
2532                irq = virq_isys_sof;
2533                break;
2534        case IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF:
2535                irq = virq_isys_eof;
2536                break;
2537        case IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR:
2538                irq = virq_isys_csi;
2539                break;
2540        case IA_CSS_IRQ_INFO_IF_ERROR:
2541                irq = virq_ifmt0_id;
2542                break;
2543#else
2544        case IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF:
2545        case IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF:
2546        case IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR:
2547        case IA_CSS_IRQ_INFO_IF_ERROR:
2548                /* Just ignore those unused IRQs without printing errors */
2549                return 0;
2550#endif
2551        case IA_CSS_IRQ_INFO_DMA_ERROR:
2552                irq = virq_dma;
2553                break;
2554        case IA_CSS_IRQ_INFO_SW_0:
2555                irq = virq_sw_pin_0;
2556                break;
2557        case IA_CSS_IRQ_INFO_SW_1:
2558                irq = virq_sw_pin_1;
2559                break;
2560        default:
2561                IA_CSS_LEAVE_ERR(-EINVAL);
2562                return -EINVAL;
2563        }
2564
2565        cnd_virq_enable_channel(irq, enable);
2566
2567        IA_CSS_LEAVE_ERR(0);
2568        return 0;
2569}
2570
2571
2572static unsigned int
2573sh_css_get_sw_interrupt_value(unsigned int irq)
2574{
2575        unsigned int irq_value;
2576
2577        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2578                            "sh_css_get_sw_interrupt_value() enter: irq=%d\n", irq);
2579        irq_value = sh_css_sp_get_sw_interrupt_value(irq);
2580        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2581                            "sh_css_get_sw_interrupt_value() leave: irq_value=%d\n", irq_value);
2582        return irq_value;
2583}
2584
2585/* configure and load the copy binary, the next binary is used to
2586   determine whether the copy binary needs to do left padding. */
2587static int load_copy_binary(
2588    struct ia_css_pipe *pipe,
2589    struct ia_css_binary *copy_binary,
2590    struct ia_css_binary *next_binary)
2591{
2592        struct ia_css_frame_info copy_out_info, copy_in_info, copy_vf_info;
2593        unsigned int left_padding;
2594        int err;
2595        struct ia_css_binary_descr copy_descr;
2596
2597        /* next_binary can be NULL */
2598        assert(pipe);
2599        assert(copy_binary);
2600        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2601                            "load_copy_binary() enter:\n");
2602
2603        if (next_binary) {
2604                copy_out_info = next_binary->in_frame_info;
2605                left_padding = next_binary->left_padding;
2606        } else {
2607                copy_out_info = pipe->output_info[0];
2608                copy_vf_info = pipe->vf_output_info[0];
2609                ia_css_frame_info_set_format(&copy_vf_info, IA_CSS_FRAME_FORMAT_YUV_LINE);
2610                left_padding = 0;
2611        }
2612
2613        ia_css_pipe_get_copy_binarydesc(pipe, &copy_descr,
2614                                        &copy_in_info, &copy_out_info,
2615                                        (next_binary) ? NULL : NULL/*TODO: &copy_vf_info*/);
2616        err = ia_css_binary_find(&copy_descr, copy_binary);
2617        if (err)
2618                return err;
2619        copy_binary->left_padding = left_padding;
2620        return 0;
2621}
2622
2623static int
2624alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time)
2625{
2626        int err = 0;
2627        struct ia_css_frame_info ref_info;
2628        enum ia_css_pipe_id pipe_id;
2629        bool continuous;
2630        unsigned int i, idx;
2631        unsigned int num_frames;
2632
2633        IA_CSS_ENTER_PRIVATE("pipe = %p, init_time = %d", pipe, init_time);
2634
2635        if ((!pipe) || (!pipe->stream)) {
2636                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2637                return -EINVAL;
2638        }
2639
2640        pipe_id = pipe->mode;
2641        continuous = pipe->stream->config.continuous;
2642
2643        if (continuous) {
2644                if (init_time) {
2645                        num_frames = pipe->stream->config.init_num_cont_raw_buf;
2646                        pipe->stream->continuous_pipe = pipe;
2647                } else {
2648                        num_frames = pipe->stream->config.target_num_cont_raw_buf;
2649                }
2650        } else {
2651                num_frames = NUM_ONLINE_INIT_CONTINUOUS_FRAMES;
2652        }
2653
2654        if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
2655                ref_info = pipe->pipe_settings.preview.preview_binary.in_frame_info;
2656        } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) {
2657                ref_info = pipe->pipe_settings.video.video_binary.in_frame_info;
2658        } else {
2659                /* should not happen */
2660                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2661                return -EINVAL;
2662        }
2663
2664#if defined(ISP2401)
2665        /* For CSI2+, the continuous frame will hold the full input frame */
2666        ref_info.res.width = pipe->stream->config.input_config.input_res.width;
2667        ref_info.res.height = pipe->stream->config.input_config.input_res.height;
2668
2669        /* Ensure padded width is aligned for 2401 */
2670        ref_info.padded_width = CEIL_MUL(ref_info.res.width, 2 * ISP_VEC_NELEMS);
2671#endif
2672
2673#if !defined(HAS_NO_PACKED_RAW_PIXELS)
2674        if (pipe->stream->config.pack_raw_pixels) {
2675                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2676                                    "alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW_PACKED\n");
2677                ref_info.format = IA_CSS_FRAME_FORMAT_RAW_PACKED;
2678        } else
2679#endif
2680        {
2681                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2682                                    "alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW\n");
2683                ref_info.format = IA_CSS_FRAME_FORMAT_RAW;
2684        }
2685
2686        /* Write format back to binary */
2687        if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
2688                pipe->pipe_settings.preview.preview_binary.in_frame_info.format =
2689                    ref_info.format;
2690        } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) {
2691                pipe->pipe_settings.video.video_binary.in_frame_info.format = ref_info.format;
2692        } else {
2693                /* should not happen */
2694                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2695                return -EINVAL;
2696        }
2697
2698        if (init_time)
2699                idx = 0;
2700        else
2701                idx = pipe->stream->config.init_num_cont_raw_buf;
2702
2703        for (i = idx; i < NUM_CONTINUOUS_FRAMES; i++) {
2704                /* free previous frame */
2705                if (pipe->continuous_frames[i]) {
2706                        ia_css_frame_free(pipe->continuous_frames[i]);
2707                        pipe->continuous_frames[i] = NULL;
2708                }
2709                /* free previous metadata buffer */
2710                ia_css_metadata_free(pipe->cont_md_buffers[i]);
2711                pipe->cont_md_buffers[i] = NULL;
2712
2713                /* check if new frame needed */
2714                if (i < num_frames) {
2715                        /* allocate new frame */
2716                        err = ia_css_frame_allocate_from_info(
2717                                  &pipe->continuous_frames[i],
2718                                  &ref_info);
2719                        if (err) {
2720                                IA_CSS_LEAVE_ERR_PRIVATE(err);
2721                                return err;
2722                        }
2723                        /* allocate metadata buffer */
2724                        pipe->cont_md_buffers[i] = ia_css_metadata_allocate(
2725                                                       &pipe->stream->info.metadata_info);
2726                }
2727        }
2728        IA_CSS_LEAVE_ERR_PRIVATE(0);
2729        return 0;
2730}
2731
2732int
2733ia_css_alloc_continuous_frame_remain(struct ia_css_stream *stream)
2734{
2735        if (!stream)
2736                return -EINVAL;
2737        return alloc_continuous_frames(stream->continuous_pipe, false);
2738}
2739
2740static int
2741load_preview_binaries(struct ia_css_pipe *pipe)
2742{
2743        struct ia_css_frame_info prev_in_info,
2744                prev_bds_out_info,
2745                prev_out_info,
2746                prev_vf_info;
2747        struct ia_css_binary_descr preview_descr;
2748        bool online;
2749        int err = 0;
2750        bool need_vf_pp = false;
2751        bool need_isp_copy_binary = false;
2752#ifdef ISP2401
2753        bool sensor = false;
2754#else
2755        bool continuous;
2756#endif
2757        /* preview only have 1 output pin now */
2758        struct ia_css_frame_info *pipe_out_info = &pipe->output_info[0];
2759        struct ia_css_preview_settings *mycs  = &pipe->pipe_settings.preview;
2760
2761        IA_CSS_ENTER_PRIVATE("");
2762        assert(pipe);
2763        assert(pipe->stream);
2764        assert(pipe->mode == IA_CSS_PIPE_ID_PREVIEW);
2765
2766        online = pipe->stream->config.online;
2767#ifdef ISP2401
2768        sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
2769#else
2770        continuous = pipe->stream->config.continuous;
2771#endif
2772
2773        if (mycs->preview_binary.info)
2774                return 0;
2775
2776        err = ia_css_util_check_input(&pipe->stream->config, false, false);
2777        if (err)
2778                return err;
2779        err = ia_css_frame_check_info(pipe_out_info);
2780        if (err)
2781                return err;
2782
2783        /* Note: the current selection of vf_pp binary and
2784         * parameterization of the preview binary contains a few pieces
2785         * of hardcoded knowledge. This needs to be cleaned up such that
2786         * the binary selection becomes more generic.
2787         * The vf_pp binary is needed if one or more of the following features
2788         * are required:
2789         * 1. YUV downscaling.
2790         * 2. Digital zoom.
2791         * 3. An output format that is not supported by the preview binary.
2792         *    In practice this means something other than yuv_line or nv12.
2793         * The decision if the vf_pp binary is needed for YUV downscaling is
2794         * made after the preview binary selection, since some preview binaries
2795         * can perform the requested YUV downscaling.
2796         * */
2797        need_vf_pp = pipe->config.enable_dz;
2798        need_vf_pp |= pipe_out_info->format != IA_CSS_FRAME_FORMAT_YUV_LINE &&
2799        !(pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12 ||
2800          pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12_16 ||
2801          pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12_TILEY);
2802
2803        /* Preview step 1 */
2804        if (pipe->vf_yuv_ds_input_info.res.width)
2805                prev_vf_info = pipe->vf_yuv_ds_input_info;
2806        else
2807                prev_vf_info = *pipe_out_info;
2808        /* If vf_pp is needed, then preview must output yuv_line.
2809         * The exception is when vf_pp is manually disabled, that is only
2810         * used in combination with a pipeline extension that requires
2811         * yuv_line as input.
2812         * */
2813        if (need_vf_pp)
2814                ia_css_frame_info_set_format(&prev_vf_info,
2815                                             IA_CSS_FRAME_FORMAT_YUV_LINE);
2816
2817        err = ia_css_pipe_get_preview_binarydesc(
2818            pipe,
2819            &preview_descr,
2820            &prev_in_info,
2821            &prev_bds_out_info,
2822            &prev_out_info,
2823            &prev_vf_info);
2824        if (err)
2825                return err;
2826        err = ia_css_binary_find(&preview_descr, &mycs->preview_binary);
2827        if (err)
2828                return err;
2829
2830        if (IS_ISP2401) {
2831                /* The delay latency determines the number of invalid frames after
2832                * a stream is started. */
2833                pipe->num_invalid_frames = pipe->dvs_frame_delay;
2834                pipe->info.num_invalid_frames = pipe->num_invalid_frames;
2835
2836                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2837                                    "load_preview_binaries() num_invalid_frames=%d dvs_frame_delay=%d\n",
2838                                    pipe->num_invalid_frames, pipe->dvs_frame_delay);
2839        }
2840
2841        /* The vf_pp binary is needed when (further) YUV downscaling is required */
2842        need_vf_pp |= mycs->preview_binary.out_frame_info[0].res.width != pipe_out_info->res.width;
2843        need_vf_pp |= mycs->preview_binary.out_frame_info[0].res.height != pipe_out_info->res.height;
2844
2845        /* When vf_pp is needed, then the output format of the selected
2846         * preview binary must be yuv_line. If this is not the case,
2847         * then the preview binary selection is done again.
2848         */
2849        if (need_vf_pp &&
2850            (mycs->preview_binary.out_frame_info[0].format != IA_CSS_FRAME_FORMAT_YUV_LINE)) {
2851                /* Preview step 2 */
2852                if (pipe->vf_yuv_ds_input_info.res.width)
2853                        prev_vf_info = pipe->vf_yuv_ds_input_info;
2854                else
2855                        prev_vf_info = *pipe_out_info;
2856
2857                ia_css_frame_info_set_format(&prev_vf_info,
2858                                             IA_CSS_FRAME_FORMAT_YUV_LINE);
2859
2860                err = ia_css_pipe_get_preview_binarydesc(
2861                    pipe,
2862                    &preview_descr,
2863                    &prev_in_info,
2864                    &prev_bds_out_info,
2865                    &prev_out_info,
2866                    &prev_vf_info);
2867                if (err)
2868                        return err;
2869                err = ia_css_binary_find(&preview_descr,
2870                                         &mycs->preview_binary);
2871                if (err)
2872                        return err;
2873        }
2874
2875        if (need_vf_pp) {
2876                struct ia_css_binary_descr vf_pp_descr;
2877
2878                /* Viewfinder post-processing */
2879                ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
2880                                                &mycs->preview_binary.out_frame_info[0],
2881                                                pipe_out_info);
2882                err = ia_css_binary_find(&vf_pp_descr,
2883                                         &mycs->vf_pp_binary);
2884                if (err)
2885                        return err;
2886        }
2887
2888#ifdef ISP2401
2889        /* When the input system is 2401, only the Direct Sensor Mode
2890         * Offline Preview uses the ISP copy binary.
2891         */
2892        need_isp_copy_binary = !online && sensor;
2893#else
2894        /* About pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY:
2895         * This is typical the case with SkyCam (which has no input system) but it also applies to all cases
2896         * where the driver chooses for memory based input frames. In these cases, a copy binary (which typical
2897         * copies sensor data to DDR) does not have much use.
2898         */
2899        if (!IS_ISP2401)
2900                need_isp_copy_binary = !online && !continuous;
2901        else
2902                need_isp_copy_binary = !online && !continuous && !(pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY);
2903#endif
2904
2905        /* Copy */
2906        if (need_isp_copy_binary) {
2907                err = load_copy_binary(pipe,
2908                                       &mycs->copy_binary,
2909                                       &mycs->preview_binary);
2910                if (err)
2911                        return err;
2912        }
2913
2914        if (pipe->shading_table) {
2915                ia_css_shading_table_free(pipe->shading_table);
2916                pipe->shading_table = NULL;
2917        }
2918
2919        return 0;
2920}
2921
2922static void
2923ia_css_binary_unload(struct ia_css_binary *binary)
2924{
2925        ia_css_binary_destroy_isp_parameters(binary);
2926}
2927
2928static int
2929unload_preview_binaries(struct ia_css_pipe *pipe)
2930{
2931        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
2932
2933        if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
2934                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2935                return -EINVAL;
2936        }
2937        ia_css_binary_unload(&pipe->pipe_settings.preview.copy_binary);
2938        ia_css_binary_unload(&pipe->pipe_settings.preview.preview_binary);
2939        ia_css_binary_unload(&pipe->pipe_settings.preview.vf_pp_binary);
2940
2941        IA_CSS_LEAVE_ERR_PRIVATE(0);
2942        return 0;
2943}
2944
2945static const struct ia_css_fw_info *last_output_firmware(
2946    const struct ia_css_fw_info *fw)
2947{
2948        const struct ia_css_fw_info *last_fw = NULL;
2949        /* fw can be NULL */
2950        IA_CSS_ENTER_LEAVE_PRIVATE("");
2951
2952        for (; fw; fw = fw->next) {
2953                const struct ia_css_fw_info *info = fw;
2954
2955                if (info->info.isp.sp.enable.output)
2956                        last_fw = fw;
2957        }
2958        return last_fw;
2959}
2960
2961static int add_firmwares(
2962    struct ia_css_pipeline *me,
2963    struct ia_css_binary *binary,
2964    const struct ia_css_fw_info *fw,
2965    const struct ia_css_fw_info *last_fw,
2966    unsigned int binary_mode,
2967    struct ia_css_frame *in_frame,
2968    struct ia_css_frame *out_frame,
2969    struct ia_css_frame *vf_frame,
2970    struct ia_css_pipeline_stage **my_stage,
2971    struct ia_css_pipeline_stage **vf_stage)
2972{
2973        int err = 0;
2974        struct ia_css_pipeline_stage *extra_stage = NULL;
2975        struct ia_css_pipeline_stage_desc stage_desc;
2976
2977        /* all args can be NULL ??? */
2978        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2979                            "add_firmwares() enter:\n");
2980
2981        for (; fw; fw = fw->next) {
2982                struct ia_css_frame *out[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL};
2983                struct ia_css_frame *in = NULL;
2984                struct ia_css_frame *vf = NULL;
2985
2986                if ((fw == last_fw) && (fw->info.isp.sp.enable.out_frame  != 0))
2987                        out[0] = out_frame;
2988
2989                if (fw->info.isp.sp.enable.in_frame != 0)
2990                        in = in_frame;
2991
2992                if (fw->info.isp.sp.enable.out_frame != 0)
2993                        vf = vf_frame;
2994
2995                ia_css_pipe_get_firmwares_stage_desc(&stage_desc, binary,
2996                                                     out, in, vf, fw, binary_mode);
2997                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
2998                                                           &extra_stage);
2999                if (err)
3000                        return err;
3001                if (fw->info.isp.sp.enable.output != 0)
3002                        in_frame = extra_stage->args.out_frame[0];
3003                if (my_stage && !*my_stage && extra_stage)
3004                        *my_stage = extra_stage;
3005                if (vf_stage && !*vf_stage && extra_stage &&
3006                    fw->info.isp.sp.enable.vf_veceven)
3007                        *vf_stage = extra_stage;
3008        }
3009        return err;
3010}
3011
3012static int add_vf_pp_stage(
3013    struct ia_css_pipe *pipe,
3014    struct ia_css_frame *in_frame,
3015    struct ia_css_frame *out_frame,
3016    struct ia_css_binary *vf_pp_binary,
3017    struct ia_css_pipeline_stage **vf_pp_stage)
3018{
3019        struct ia_css_pipeline *me = NULL;
3020        const struct ia_css_fw_info *last_fw = NULL;
3021        int err = 0;
3022        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3023        struct ia_css_pipeline_stage_desc stage_desc;
3024
3025        /* out_frame can be NULL ??? */
3026
3027        if (!pipe)
3028                return -EINVAL;
3029        if (!in_frame)
3030                return -EINVAL;
3031        if (!vf_pp_binary)
3032                return -EINVAL;
3033        if (!vf_pp_stage)
3034                return -EINVAL;
3035
3036        ia_css_pipe_util_create_output_frames(out_frames);
3037        me = &pipe->pipeline;
3038
3039        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3040                            "add_vf_pp_stage() enter:\n");
3041
3042        *vf_pp_stage = NULL;
3043
3044        last_fw = last_output_firmware(pipe->vf_stage);
3045        if (!pipe->extra_config.disable_vf_pp) {
3046                if (last_fw) {
3047                        ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3048                        ia_css_pipe_get_generic_stage_desc(&stage_desc, vf_pp_binary,
3049                                                           out_frames, in_frame, NULL);
3050                } else {
3051                        ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3052                        ia_css_pipe_get_generic_stage_desc(&stage_desc, vf_pp_binary,
3053                                                           out_frames, in_frame, NULL);
3054                }
3055                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, vf_pp_stage);
3056                if (err)
3057                        return err;
3058                in_frame = (*vf_pp_stage)->args.out_frame[0];
3059        }
3060        err = add_firmwares(me, vf_pp_binary, pipe->vf_stage, last_fw,
3061                            IA_CSS_BINARY_MODE_VF_PP,
3062                            in_frame, out_frame, NULL,
3063                            vf_pp_stage, NULL);
3064        return err;
3065}
3066
3067static int add_yuv_scaler_stage(
3068    struct ia_css_pipe *pipe,
3069    struct ia_css_pipeline *me,
3070    struct ia_css_frame *in_frame,
3071    struct ia_css_frame *out_frame,
3072    struct ia_css_frame *internal_out_frame,
3073    struct ia_css_binary *yuv_scaler_binary,
3074    struct ia_css_pipeline_stage **pre_vf_pp_stage)
3075{
3076        const struct ia_css_fw_info *last_fw;
3077        int err = 0;
3078        struct ia_css_frame *vf_frame = NULL;
3079        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3080        struct ia_css_pipeline_stage_desc stage_desc;
3081
3082        /* out_frame can be NULL ??? */
3083        assert(in_frame);
3084        assert(pipe);
3085        assert(me);
3086        assert(yuv_scaler_binary);
3087        assert(pre_vf_pp_stage);
3088        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3089                            "add_yuv_scaler_stage() enter:\n");
3090
3091        *pre_vf_pp_stage = NULL;
3092        ia_css_pipe_util_create_output_frames(out_frames);
3093
3094        last_fw = last_output_firmware(pipe->output_stage);
3095
3096        if (last_fw) {
3097                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3098                ia_css_pipe_get_generic_stage_desc(&stage_desc,
3099                                                   yuv_scaler_binary, out_frames, in_frame, vf_frame);
3100        } else {
3101                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3102                ia_css_pipe_util_set_output_frames(out_frames, 1, internal_out_frame);
3103                ia_css_pipe_get_generic_stage_desc(&stage_desc,
3104                                                   yuv_scaler_binary, out_frames, in_frame, vf_frame);
3105        }
3106        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3107                                                   pre_vf_pp_stage);
3108        if (err)
3109                return err;
3110        in_frame = (*pre_vf_pp_stage)->args.out_frame[0];
3111
3112        err = add_firmwares(me, yuv_scaler_binary, pipe->output_stage, last_fw,
3113                            IA_CSS_BINARY_MODE_CAPTURE_PP,
3114                            in_frame, out_frame, vf_frame,
3115                            NULL, pre_vf_pp_stage);
3116        /* If a firmware produce vf_pp output, we set that as vf_pp input */
3117        (*pre_vf_pp_stage)->args.vf_downscale_log2 =
3118            yuv_scaler_binary->vf_downscale_log2;
3119
3120        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3121                            "add_yuv_scaler_stage() leave:\n");
3122        return err;
3123}
3124
3125static int add_capture_pp_stage(
3126    struct ia_css_pipe *pipe,
3127    struct ia_css_pipeline *me,
3128    struct ia_css_frame *in_frame,
3129    struct ia_css_frame *out_frame,
3130    struct ia_css_binary *capture_pp_binary,
3131    struct ia_css_pipeline_stage **capture_pp_stage)
3132{
3133        const struct ia_css_fw_info *last_fw = NULL;
3134        int err = 0;
3135        struct ia_css_frame *vf_frame = NULL;
3136        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3137        struct ia_css_pipeline_stage_desc stage_desc;
3138
3139        /* out_frame can be NULL ??? */
3140        assert(in_frame);
3141        assert(pipe);
3142        assert(me);
3143        assert(capture_pp_binary);
3144        assert(capture_pp_stage);
3145        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3146                            "add_capture_pp_stage() enter:\n");
3147
3148        *capture_pp_stage = NULL;
3149        ia_css_pipe_util_create_output_frames(out_frames);
3150
3151        last_fw = last_output_firmware(pipe->output_stage);
3152        err = ia_css_frame_allocate_from_info(&vf_frame,
3153                                              &capture_pp_binary->vf_frame_info);
3154        if (err)
3155                return err;
3156        if (last_fw)    {
3157                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3158                ia_css_pipe_get_generic_stage_desc(&stage_desc,
3159                                                   capture_pp_binary, out_frames, NULL, vf_frame);
3160        } else {
3161                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3162                ia_css_pipe_get_generic_stage_desc(&stage_desc,
3163                                                   capture_pp_binary, out_frames, NULL, vf_frame);
3164        }
3165        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3166                                                   capture_pp_stage);
3167        if (err)
3168                return err;
3169        err = add_firmwares(me, capture_pp_binary, pipe->output_stage, last_fw,
3170                            IA_CSS_BINARY_MODE_CAPTURE_PP,
3171                            in_frame, out_frame, vf_frame,
3172                            NULL, capture_pp_stage);
3173        /* If a firmware produce vf_pp output, we set that as vf_pp input */
3174        if (*capture_pp_stage) {
3175                (*capture_pp_stage)->args.vf_downscale_log2 =
3176                    capture_pp_binary->vf_downscale_log2;
3177        }
3178        return err;
3179}
3180
3181static void sh_css_setup_queues(void)
3182{
3183        const struct ia_css_fw_info *fw;
3184        unsigned int HIVE_ADDR_host_sp_queues_initialized;
3185
3186        sh_css_hmm_buffer_record_init();
3187
3188        sh_css_event_init_irq_mask();
3189
3190        fw = &sh_css_sp_fw;
3191        HIVE_ADDR_host_sp_queues_initialized =
3192            fw->info.sp.host_sp_queues_initialized;
3193
3194        ia_css_bufq_init();
3195
3196        /* set "host_sp_queues_initialized" to "true" */
3197        sp_dmem_store_uint32(SP0_ID,
3198                             (unsigned int)sp_address_of(host_sp_queues_initialized),
3199                             (uint32_t)(1));
3200        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "sh_css_setup_queues() leave:\n");
3201}
3202
3203static int
3204init_vf_frameinfo_defaults(struct ia_css_pipe *pipe,
3205                           struct ia_css_frame *vf_frame, unsigned int idx)
3206{
3207        int err = 0;
3208        unsigned int thread_id;
3209        enum sh_css_queue_id queue_id;
3210
3211        assert(vf_frame);
3212
3213        sh_css_pipe_get_viewfinder_frame_info(pipe, &vf_frame->info, idx);
3214        vf_frame->contiguous = false;
3215        vf_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3216        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3217        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, thread_id, &queue_id);
3218        vf_frame->dynamic_queue_id = queue_id;
3219        vf_frame->buf_type = IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx;
3220
3221        err = ia_css_frame_init_planes(vf_frame);
3222        return err;
3223}
3224
3225#ifdef ISP2401
3226static unsigned int
3227get_crop_lines_for_bayer_order(
3228    const struct ia_css_stream_config *config)
3229{
3230        assert(config);
3231        if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR)
3232            || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
3233                return 1;
3234
3235        return 0;
3236}
3237
3238static unsigned int
3239get_crop_columns_for_bayer_order(
3240    const struct ia_css_stream_config *config)
3241{
3242        assert(config);
3243        if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB)
3244            || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
3245                return 1;
3246
3247        return 0;
3248}
3249
3250/* This function is to get the sum of all extra pixels in addition to the effective
3251 * input, it includes dvs envelop and filter run-in */
3252static void get_pipe_extra_pixel(struct ia_css_pipe *pipe,
3253                                 unsigned int *extra_row, unsigned int *extra_column)
3254{
3255        enum ia_css_pipe_id pipe_id = pipe->mode;
3256        unsigned int left_cropping = 0, top_cropping = 0;
3257        unsigned int i;
3258        struct ia_css_resolution dvs_env = pipe->config.dvs_envelope;
3259
3260        /* The dvs envelope info may not be correctly sent down via pipe config
3261         * The check is made and the correct value is populated in the binary info
3262         * Use this value when computing crop, else excess lines may get trimmed
3263         */
3264        switch (pipe_id) {
3265        case IA_CSS_PIPE_ID_PREVIEW:
3266                if (pipe->pipe_settings.preview.preview_binary.info) {
3267                        left_cropping =
3268                            pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.left_cropping;
3269                        top_cropping =
3270                            pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.top_cropping;
3271                }
3272                dvs_env = pipe->pipe_settings.preview.preview_binary.dvs_envelope;
3273                break;
3274        case IA_CSS_PIPE_ID_VIDEO:
3275                if (pipe->pipe_settings.video.video_binary.info) {
3276                        left_cropping =
3277                            pipe->pipe_settings.video.video_binary.info->sp.pipeline.left_cropping;
3278                        top_cropping =
3279                            pipe->pipe_settings.video.video_binary.info->sp.pipeline.top_cropping;
3280                }
3281                dvs_env = pipe->pipe_settings.video.video_binary.dvs_envelope;
3282                break;
3283        case IA_CSS_PIPE_ID_CAPTURE:
3284                for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
3285                        if (pipe->pipe_settings.capture.primary_binary[i].info) {
3286                                left_cropping +=
3287                                    pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.left_cropping;
3288                                top_cropping +=
3289                                    pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.top_cropping;
3290                        }
3291                        dvs_env.width +=
3292                            pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.width;
3293                        dvs_env.height +=
3294                            pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.height;
3295                }
3296                break;
3297        default:
3298                break;
3299        }
3300
3301        *extra_row = top_cropping + dvs_env.height;
3302        *extra_column = left_cropping + dvs_env.width;
3303}
3304
3305void
3306ia_css_get_crop_offsets(
3307    struct ia_css_pipe *pipe,
3308    struct ia_css_frame_info *in_frame)
3309{
3310        unsigned int row = 0;
3311        unsigned int column = 0;
3312        struct ia_css_resolution *input_res;
3313        struct ia_css_resolution *effective_res;
3314        unsigned int extra_row = 0, extra_col = 0;
3315        unsigned int min_reqd_height, min_reqd_width;
3316
3317        assert(pipe);
3318        assert(pipe->stream);
3319        assert(in_frame);
3320
3321        IA_CSS_ENTER_PRIVATE("pipe = %p effective_wd = %u effective_ht = %u",
3322                             pipe, pipe->config.input_effective_res.width,
3323                             pipe->config.input_effective_res.height);
3324
3325        input_res = &pipe->stream->config.input_config.input_res;
3326#ifndef ISP2401
3327        effective_res = &pipe->stream->config.input_config.effective_res;
3328#else
3329        effective_res = &pipe->config.input_effective_res;
3330#endif
3331
3332        get_pipe_extra_pixel(pipe, &extra_row, &extra_col);
3333
3334        in_frame->raw_bayer_order = pipe->stream->config.input_config.bayer_order;
3335
3336        min_reqd_height = effective_res->height + extra_row;
3337        min_reqd_width = effective_res->width + extra_col;
3338
3339        if (input_res->height > min_reqd_height) {
3340                row = (input_res->height - min_reqd_height) / 2;
3341                row &= ~0x1;
3342        }
3343        if (input_res->width > min_reqd_width) {
3344                column = (input_res->width - min_reqd_width) / 2;
3345                column &= ~0x1;
3346        }
3347
3348        /*
3349         * TODO:
3350         * 1. Require the special support for RAW10 packed mode.
3351         * 2. Require the special support for the online use cases.
3352         */
3353
3354        /* ISP expects GRBG bayer order, we skip one line and/or one row
3355         * to correct in case the input bayer order is different.
3356         */
3357        column += get_crop_columns_for_bayer_order(&pipe->stream->config);
3358        row += get_crop_lines_for_bayer_order(&pipe->stream->config);
3359
3360        in_frame->crop_info.start_column = column;
3361        in_frame->crop_info.start_line = row;
3362
3363        IA_CSS_LEAVE_PRIVATE("void start_col: %u start_row: %u", column, row);
3364
3365        return;
3366}
3367#endif
3368
3369static int
3370init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
3371                                  struct ia_css_frame *frame, enum ia_css_frame_format format)
3372{
3373        struct ia_css_frame *in_frame;
3374        int err = 0;
3375        unsigned int thread_id;
3376        enum sh_css_queue_id queue_id;
3377
3378        assert(frame);
3379        in_frame = frame;
3380
3381        in_frame->info.format = format;
3382
3383#ifdef ISP2401
3384        if (format == IA_CSS_FRAME_FORMAT_RAW)
3385                in_frame->info.format = (pipe->stream->config.pack_raw_pixels) ?
3386                IA_CSS_FRAME_FORMAT_RAW_PACKED : IA_CSS_FRAME_FORMAT_RAW;
3387#endif
3388
3389        in_frame->info.res.width = pipe->stream->config.input_config.input_res.width;
3390        in_frame->info.res.height = pipe->stream->config.input_config.input_res.height;
3391        in_frame->info.raw_bit_depth =
3392        ia_css_pipe_util_pipe_input_format_bpp(pipe);
3393        ia_css_frame_info_set_width(&in_frame->info, pipe->stream->config.input_config.input_res.width, 0);
3394        in_frame->contiguous = false;
3395        in_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3396        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3397        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id);
3398        in_frame->dynamic_queue_id = queue_id;
3399        in_frame->buf_type = IA_CSS_BUFFER_TYPE_INPUT_FRAME;
3400#ifdef ISP2401
3401        ia_css_get_crop_offsets(pipe, &in_frame->info);
3402#endif
3403        err = ia_css_frame_init_planes(in_frame);
3404
3405        ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3406                            "init_in_frameinfo_memory_defaults() bayer_order = %d:\n", in_frame->info.raw_bayer_order);
3407
3408        return err;
3409}
3410
3411static int
3412init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
3413                            struct ia_css_frame *out_frame, unsigned int idx)
3414{
3415        int err = 0;
3416        unsigned int thread_id;
3417        enum sh_css_queue_id queue_id;
3418
3419        assert(out_frame);
3420
3421        sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, idx);
3422        out_frame->contiguous = false;
3423        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3424        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3425        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, thread_id, &queue_id);
3426        out_frame->dynamic_queue_id = queue_id;
3427        out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx;
3428        err = ia_css_frame_init_planes(out_frame);
3429
3430        return err;
3431}
3432
3433/* Create stages for video pipe */
3434static int create_host_video_pipeline(struct ia_css_pipe *pipe)
3435{
3436        struct ia_css_pipeline_stage_desc stage_desc;
3437        struct ia_css_binary *copy_binary, *video_binary,
3438                       *yuv_scaler_binary, *vf_pp_binary;
3439        struct ia_css_pipeline_stage *copy_stage  = NULL;
3440        struct ia_css_pipeline_stage *video_stage = NULL;
3441        struct ia_css_pipeline_stage *yuv_scaler_stage  = NULL;
3442        struct ia_css_pipeline_stage *vf_pp_stage = NULL;
3443        struct ia_css_pipeline *me;
3444        struct ia_css_frame *in_frame = NULL;
3445        struct ia_css_frame *out_frame;
3446        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3447        struct ia_css_frame *vf_frame = NULL;
3448        int err = 0;
3449        bool need_copy   = false;
3450        bool need_vf_pp  = false;
3451        bool need_yuv_pp = false;
3452        bool need_in_frameinfo_memory = false;
3453
3454        unsigned int i, num_yuv_scaler;
3455        bool *is_output_stage = NULL;
3456
3457        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3458        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
3459                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3460                return -EINVAL;
3461        }
3462        ia_css_pipe_util_create_output_frames(out_frames);
3463        out_frame = &pipe->out_frame_struct;
3464
3465        /* pipeline already created as part of create_host_pipeline_structure */
3466        me = &pipe->pipeline;
3467        ia_css_pipeline_clean(me);
3468
3469        me->dvs_frame_delay = pipe->dvs_frame_delay;
3470
3471#ifdef ISP2401
3472        /* When the input system is 2401, always enable 'in_frameinfo_memory'
3473         * except for the following: online or continuous
3474         */
3475        need_in_frameinfo_memory = !(pipe->stream->config.online ||
3476                                     pipe->stream->config.continuous);
3477#else
3478        /* Construct in_frame info (only in case we have dynamic input */
3479        need_in_frameinfo_memory = pipe->stream->config.mode ==
3480                                   IA_CSS_INPUT_MODE_MEMORY;
3481#endif
3482
3483        /* Construct in_frame info (only in case we have dynamic input */
3484        if (need_in_frameinfo_memory) {
3485                in_frame = &pipe->in_frame_struct;
3486                err = init_in_frameinfo_memory_defaults(pipe, in_frame,
3487                                                        IA_CSS_FRAME_FORMAT_RAW);
3488                if (err)
3489                        goto ERR;
3490        }
3491
3492        out_frame->data = 0;
3493        err = init_out_frameinfo_defaults(pipe, out_frame, 0);
3494        if (err)
3495                goto ERR;
3496
3497        if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
3498                vf_frame = &pipe->vf_frame_struct;
3499                vf_frame->data = 0;
3500                err = init_vf_frameinfo_defaults(pipe, vf_frame, 0);
3501                if (err)
3502                        goto ERR;
3503        }
3504
3505        copy_binary  = &pipe->pipe_settings.video.copy_binary;
3506        video_binary = &pipe->pipe_settings.video.video_binary;
3507        vf_pp_binary = &pipe->pipe_settings.video.vf_pp_binary;
3508
3509        yuv_scaler_binary = pipe->pipe_settings.video.yuv_scaler_binary;
3510        num_yuv_scaler  = pipe->pipe_settings.video.num_yuv_scaler;
3511        is_output_stage = pipe->pipe_settings.video.is_output_stage;
3512
3513        need_copy   = (copy_binary && copy_binary->info);
3514        need_vf_pp  = (vf_pp_binary && vf_pp_binary->info);
3515        need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
3516
3517        if (need_copy) {
3518                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3519                ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
3520                                                   out_frames, NULL, NULL);
3521                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3522                                                           &copy_stage);
3523                if (err)
3524                        goto ERR;
3525                in_frame = me->stages->args.out_frame[0];
3526        } else if (pipe->stream->config.continuous) {
3527#ifdef ISP2401
3528                /* When continuous is enabled, configure in_frame with the
3529                 * last pipe, which is the copy pipe.
3530                 */
3531                in_frame = pipe->stream->last_pipe->continuous_frames[0];
3532#else
3533                in_frame = pipe->continuous_frames[0];
3534#endif
3535        }
3536
3537        ia_css_pipe_util_set_output_frames(out_frames, 0,
3538                                           need_yuv_pp ? NULL : out_frame);
3539
3540        /* when the video binary supports a second output pin,
3541           it can directly produce the vf_frame.  */
3542        if (need_vf_pp) {
3543                ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
3544                                                   out_frames, in_frame, NULL);
3545        } else {
3546                ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
3547                                                   out_frames, in_frame, vf_frame);
3548        }
3549        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3550                                                   &video_stage);
3551        if (err)
3552                goto ERR;
3553
3554        /* If we use copy iso video, the input must be yuv iso raw */
3555        if (video_stage) {
3556                video_stage->args.copy_vf =
3557                    video_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
3558                video_stage->args.copy_output = video_stage->args.copy_vf;
3559        }
3560
3561        /* when the video binary supports only 1 output pin, vf_pp is needed to
3562        produce the vf_frame.*/
3563        if (need_vf_pp && video_stage) {
3564                in_frame = video_stage->args.out_vf_frame;
3565                err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
3566                                      &vf_pp_stage);
3567                if (err)
3568                        goto ERR;
3569        }
3570        if (video_stage) {
3571                int frm;
3572
3573                for (frm = 0; frm < NUM_TNR_FRAMES; frm++) {
3574                        video_stage->args.tnr_frames[frm] =
3575                            pipe->pipe_settings.video.tnr_frames[frm];
3576                }
3577                for (frm = 0; frm < MAX_NUM_VIDEO_DELAY_FRAMES; frm++) {
3578                        video_stage->args.delay_frames[frm] =
3579                            pipe->pipe_settings.video.delay_frames[frm];
3580                }
3581        }
3582
3583        /* Append Extension on Video out, if enabled */
3584        if (!need_vf_pp && video_stage && pipe->config.acc_extension &&
3585            (pipe->config.acc_extension->info.isp.type == IA_CSS_ACC_OUTPUT)) {
3586                struct ia_css_frame *out = NULL;
3587                struct ia_css_frame *in = NULL;
3588
3589                if ((pipe->config.acc_extension->info.isp.sp.enable.output) &&
3590                    (pipe->config.acc_extension->info.isp.sp.enable.in_frame) &&
3591                    (pipe->config.acc_extension->info.isp.sp.enable.out_frame)) {
3592                        /* In/Out Frame mapping to support output frame extension.*/
3593                        out = video_stage->args.out_frame[0];
3594                        err = ia_css_frame_allocate_from_info(&in, &pipe->output_info[0]);
3595                        if (err)
3596                                goto ERR;
3597                        video_stage->args.out_frame[0] = in;
3598                }
3599
3600                err = add_firmwares(me, video_binary, pipe->output_stage,
3601                                    last_output_firmware(pipe->output_stage),
3602                                    IA_CSS_BINARY_MODE_VIDEO,
3603                                    in, out, NULL, &video_stage, NULL);
3604                if (err)
3605                        goto ERR;
3606        }
3607
3608        if (need_yuv_pp && video_stage) {
3609                struct ia_css_frame *tmp_in_frame = video_stage->args.out_frame[0];
3610                struct ia_css_frame *tmp_out_frame = NULL;
3611
3612                for (i = 0; i < num_yuv_scaler; i++) {
3613                        tmp_out_frame = is_output_stage[i] ? out_frame : NULL;
3614
3615                        err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
3616                                                   tmp_out_frame, NULL,
3617                                                   &yuv_scaler_binary[i],
3618                                                   &yuv_scaler_stage);
3619
3620                        if (err) {
3621                                IA_CSS_LEAVE_ERR_PRIVATE(err);
3622                                return err;
3623                        }
3624                        /* we use output port 1 as internal output port */
3625                        if (yuv_scaler_stage)
3626                                tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
3627                }
3628        }
3629
3630        pipe->pipeline.acquire_isp_each_stage = false;
3631        ia_css_pipeline_finalize_stages(&pipe->pipeline,
3632                                        pipe->stream->config.continuous);
3633
3634ERR:
3635        IA_CSS_LEAVE_ERR_PRIVATE(err);
3636        return err;
3637}
3638
3639static int
3640create_host_acc_pipeline(struct ia_css_pipe *pipe)
3641{
3642        int err = 0;
3643        const struct ia_css_fw_info *fw;
3644        unsigned int i;
3645
3646        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3647        if ((!pipe) || (!pipe->stream)) {
3648                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3649                return -EINVAL;
3650        }
3651
3652        pipe->pipeline.num_execs = pipe->config.acc_num_execs;
3653        /* Reset pipe_qos_config to default disable all QOS extension stages */
3654        if (pipe->config.acc_extension)
3655                pipe->pipeline.pipe_qos_config = 0;
3656
3657        fw = pipe->vf_stage;
3658        for (i = 0; fw; fw = fw->next) {
3659                err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
3660                if (err)
3661                        goto ERR;
3662        }
3663
3664        for (i = 0; i < pipe->config.num_acc_stages; i++) {
3665                struct ia_css_fw_info *fw = pipe->config.acc_stages[i];
3666
3667                err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
3668                if (err)
3669                        goto ERR;
3670        }
3671
3672        ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
3673
3674ERR:
3675        IA_CSS_LEAVE_ERR_PRIVATE(err);
3676        return err;
3677}
3678
3679/* Create stages for preview */
3680static int
3681create_host_preview_pipeline(struct ia_css_pipe *pipe)
3682{
3683        struct ia_css_pipeline_stage *copy_stage = NULL;
3684        struct ia_css_pipeline_stage *preview_stage = NULL;
3685        struct ia_css_pipeline_stage *vf_pp_stage = NULL;
3686        struct ia_css_pipeline_stage_desc stage_desc;
3687        struct ia_css_pipeline *me = NULL;
3688        struct ia_css_binary *copy_binary, *preview_binary, *vf_pp_binary = NULL;
3689        struct ia_css_frame *in_frame = NULL;
3690        int err = 0;
3691        struct ia_css_frame *out_frame;
3692        struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3693        bool need_in_frameinfo_memory = false;
3694#ifdef ISP2401
3695        bool sensor = false;
3696        bool buffered_sensor = false;
3697        bool online = false;
3698        bool continuous = false;
3699#endif
3700
3701        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3702        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
3703                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3704                return -EINVAL;
3705        }
3706
3707        ia_css_pipe_util_create_output_frames(out_frames);
3708        /* pipeline already created as part of create_host_pipeline_structure */
3709        me = &pipe->pipeline;
3710        ia_css_pipeline_clean(me);
3711
3712#ifdef ISP2401
3713        /* When the input system is 2401, always enable 'in_frameinfo_memory'
3714         * except for the following:
3715         * - Direct Sensor Mode Online Preview
3716         * - Buffered Sensor Mode Online Preview
3717         * - Direct Sensor Mode Continuous Preview
3718         * - Buffered Sensor Mode Continuous Preview
3719         */
3720        sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
3721        buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
3722        online = pipe->stream->config.online;
3723        continuous = pipe->stream->config.continuous;
3724        need_in_frameinfo_memory =
3725        !((sensor && (online || continuous)) || (buffered_sensor && (online || continuous)));
3726#else
3727        /* Construct in_frame info (only in case we have dynamic input */
3728        need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
3729#endif
3730        if (need_in_frameinfo_memory) {
3731                err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
3732                                                        IA_CSS_FRAME_FORMAT_RAW);
3733                if (err)
3734                        goto ERR;
3735
3736                in_frame = &me->in_frame;
3737        } else {
3738                in_frame = NULL;
3739        }
3740
3741        err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
3742        if (err)
3743                goto ERR;
3744        out_frame = &me->out_frame[0];
3745
3746        copy_binary    = &pipe->pipe_settings.preview.copy_binary;
3747        preview_binary = &pipe->pipe_settings.preview.preview_binary;
3748        if (pipe->pipe_settings.preview.vf_pp_binary.info)
3749                vf_pp_binary = &pipe->pipe_settings.preview.vf_pp_binary;
3750
3751        if (pipe->pipe_settings.preview.copy_binary.info) {
3752                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3753                ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
3754                                                   out_frames, NULL, NULL);
3755                err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3756                                                           &copy_stage);
3757                if (err)
3758                        goto ERR;
3759                in_frame = me->stages->args.out_frame[0];
3760        } else if (pipe->stream->config.continuous) {
3761#ifdef ISP2401
3762                /* When continuous is enabled, configure in_frame with the
3763                 * last pipe, which is the copy pipe.
3764                 */
3765                if (continuous || !online)
3766                        in_frame = pipe->stream->last_pipe->continuous_frames[0];
3767
3768#else
3769                in_frame = pipe->continuous_frames[0];
3770#endif
3771        }
3772
3773        if (vf_pp_binary) {
3774                ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3775                ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
3776                                                   out_frames, in_frame, NULL);
3777        } else {
3778                ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3779                ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
3780                                                   out_frames, in_frame, NULL);
3781        }
3782        err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3783                                                   &preview_stage);
3784        if (err)
3785                goto ERR;
3786        /* If we use copy iso preview, the input must be yuv iso raw */
3787        preview_stage->args.copy_vf =
3788            preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
3789        preview_stage->args.copy_output = !preview_stage->args.copy_vf;
3790        if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) {
3791                /* in case of copy, use the vf frame as output frame */
3792                preview_stage->args.out_vf_frame =
3793                    preview_stage->args.out_frame[0];
3794        }
3795        if (vf_pp_binary) {
3796                if (preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)
3797                        in_frame = preview_stage->args.out_vf_frame;
3798                else
3799                        in_frame = preview_stage->args.out_frame[0];
3800                err = add_vf_pp_stage(pipe, in_frame, out_frame, vf_pp_binary,
3801                                      &vf_pp_stage);
3802                if (err)
3803                        goto ERR;
3804        }
3805
3806        pipe->pipeline.acquire_isp_each_stage = false;
3807        ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
3808
3809ERR:
3810        IA_CSS_LEAVE_ERR_PRIVATE(err);
3811        return err;
3812}
3813
3814static void send_raw_frames(struct ia_css_pipe *pipe)
3815{
3816        if (pipe->stream->config.continuous) {
3817                unsigned int i;
3818
3819                sh_css_update_host2sp_cont_num_raw_frames
3820                (pipe->stream->config.init_num_cont_raw_buf, true);
3821                sh_css_update_host2sp_cont_num_raw_frames
3822                (pipe->stream->config.target_num_cont_raw_buf, false);
3823
3824                /* Hand-over all the SP-internal buffers */
3825                for (i = 0; i < pipe->stream->config.init_num_cont_raw_buf; i++) {
3826                        sh_css_update_host2sp_offline_frame(i,
3827                                                            pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
3828                }
3829        }
3830
3831        return;
3832}
3833
3834static int
3835preview_start(struct ia_css_pipe *pipe)
3836{
3837        int err = 0;
3838        struct ia_css_pipe *copy_pipe, *capture_pipe;
3839        struct ia_css_pipe *acc_pipe;
3840        enum sh_css_pipe_config_override copy_ovrd;
3841        enum ia_css_input_mode preview_pipe_input_mode;
3842        const struct ia_css_coordinate *coord = NULL;
3843        const struct ia_css_isp_parameters *params = NULL;
3844
3845        IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3846        if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
3847                IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3848                return -EINVAL;
3849        }
3850
3851        preview_pipe_input_mode = pipe->stream->config.mode;
3852
3853        copy_pipe    = pipe->pipe_settings.preview.copy_pipe;
3854        capture_pipe = pipe->pipe_settings.preview.capture_pipe;
3855        acc_pipe     = pipe->pipe_settings.preview.acc_pipe;
3856
3857        sh_css_metrics_start_frame();
3858
3859        /* multi stream video needs mipi buffers */
3860        err = send_mipi_frames(pipe);
3861        if (err) {
3862                IA_CSS_LEAVE_ERR_PRIVATE(err);
3863                return err;
3864        }
3865        send_raw_frames(pipe);
3866
3867        {
3868                unsigned int thread_id;
3869
3870                ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3871                copy_ovrd = 1 << thread_id;
3872
3873                if (pipe->stream->cont_capt) {
3874                        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
3875                                                         &thread_id);
3876                        copy_ovrd |= 1 << thread_id;
3877                }
3878        }
3879
3880        if (IS_ISP2401) {
3881                coord = &pipe->config.internal_frame_origin_bqs_on_sctbl;
3882                params = pipe->stream->isp_params_configs;
3883        }
3884
3885        /* Construct and load the copy pipe */
3886        if (pipe->stream->config.continuous) {
3887                sh_css_sp_init_pipeline(&copy_pipe->pipeline,
3888                                        IA_CSS_PIPE_ID_COPY,
3889                                        (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
3890                                        false,
3891                                        pipe->stream->config.pixels_per_clock == 2, false,
3892                                        false, pipe->required_bds_factor,
3893                                        copy_ovrd,
3894                                        pipe->stream->config.mode,
3895                                        &pipe->stream->config.metadata_config,
3896                                        &pipe->stream->info.metadata_info,
3897                                        pipe->stream->config.source.port.port,
3898                                        coord,
3899                                        params);
3900
3901                /* make the preview pipe start with mem mode input, copy handles
3902                   the actual mode */
3903                preview_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY;
3904        }
3905
3906        /* Construct and load the capture pipe */
3907        if (pipe->stream->cont_capt) {
3908                sh_css_sp_init_pipeline(&capture_pipe->pipeline,
3909                                        IA_CSS_PIPE_ID_CAPTURE,
3910                                        (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
3911                                        capture_pipe->config.default_capture_config.enable_xnr != 0,
3912                                        capture_pipe->stream->config.pixels_per_clock == 2,
3913                                        true, /* continuous */
3914                                        false, /* offline */
3915                                        capture_pipe->required_bds_factor,
3916                                        0,
3917                                        IA_CSS_INPUT_MODE_MEMORY,
3918                                        &pipe->stream->config.metadata_config,
3919                                        &pipe->stream->info.metadata_info,
3920                                        (enum mipi_port_id)0,
3921                                        coord,
3922                                        params);
3923        }
3924
3925        if (acc_pipe) {
3926                sh_css_sp_init_pipeline(&acc_pipe->pipeline,
3927                                        IA_CSS_PIPE_ID_ACC,
3928                                        (uint8_t)ia_css_pipe_get_pipe_num(acc_pipe),
3929                                        false,
3930                                        pipe->stream->config.pixels_per_clock == 2,
3931                                        false, /* continuous */
3932                                        false, /* offline */
3933                                        pipe->required_bds_factor,
3934                                        0,
3935                                        IA_CSS_INPUT_MODE_MEMORY,
3936                                        NULL,
3937                                        NULL,
3938                                        (enum mipi_port_id)0,
3939                                        coord,
3940                                        params);
3941        }
3942
3943        start_pipe(pipe, copy_ovrd, preview_pipe_input_mode);
3944
3945        IA_CSS_LEAVE_ERR_PRIVATE(err);
3946        return err;
3947}
3948
3949int
3950ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
3951                           const struct ia_css_buffer *buffer)
3952{
3953        int return_err = 0;
3954        unsigned int thread_id;
3955        enum sh_css_queue_id queue_id;
3956        struct ia_css_pipeline *pipeline;
3957        struct ia_css_pipeline_stage *stage;
3958        struct ia_css_rmgr_vbuf_handle p_vbuf;
3959        struct ia_css_rmgr_vbuf_handle *h_vbuf;
3960        struct sh_css_hmm_buffer ddr_buffer;
3961        enum ia_css_buffer_type buf_type;
3962        enum ia_css_pipe_id pipe_id;
3963        bool ret_err;
3964
3965        IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
3966
3967        if ((!pipe) || (!buffer)) {
3968                IA_CSS_LEAVE_ERR(-EINVAL);
3969                return -EINVAL;
3970        }
3971
3972        buf_type = buffer->type;
3973        /* following code will be enabled when IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
3974           is removed */
3975#if 0
3976        if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
3977                bool found_pipe = false;
3978
3979                for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
3980                        if ((buffer->data.frame->info.res.width == pipe->output_info[i].res.width) &&
3981                            (buffer->data.frame->info.res.height == pipe->output_info[i].res.height)) {
3982                                buf_type += i;
3983                                found_pipe = true;
3984                                break;
3985                        }
3986                }
3987                if (!found_pipe)
3988                        return -EINVAL;
3989        }
3990        if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
3991                bool found_pipe = false;
3992
3993                for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
3994                        if ((buffer->data.frame->info.res.width == pipe->vf_output_info[i].res.width) &&
3995                            (buffer->data.frame->info.res.height == pipe->vf_output_info[i].res.height)) {
3996                                buf_type +=