| /* |
| * Support for Intel Camera Imaging ISP subsystem. |
| * Copyright (c) 2015, Intel Corporation. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms and conditions of the GNU General Public License, |
| * version 2, as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| */ |
| |
| #include "sh_css_sp.h" |
| |
| #if !defined(HAS_NO_INPUT_FORMATTER) |
| #include "input_formatter.h" |
| #endif |
| |
| #include "dma.h" /* N_DMA_CHANNEL_ID */ |
| |
| #include "ia_css_buffer.h" |
| #include "ia_css_binary.h" |
| #include "sh_css_hrt.h" |
| #include "sh_css_defs.h" |
| #include "sh_css_internal.h" |
| #include "ia_css_control.h" |
| #include "ia_css_debug.h" |
| #include "ia_css_debug_pipe.h" |
| #include "ia_css_event_public.h" |
| #include "ia_css_mmu.h" |
| #include "ia_css_stream.h" |
| #include "ia_css_isp_param.h" |
| #include "sh_css_params.h" |
| #include "sh_css_legacy.h" |
| #include "ia_css_frame_comm.h" |
| #if !defined(HAS_NO_INPUT_SYSTEM) |
| #include "ia_css_isys.h" |
| #endif |
| |
| #include "gdc_device.h" /* HRT_GDC_N */ |
| |
| /*#include "sp.h"*/ /* host2sp_enqueue_frame_data() */ |
| |
| #include "memory_access.h" |
| |
| #include "assert_support.h" |
| #include "platform_support.h" /* hrt_sleep() */ |
| |
| #include "sw_event_global.h" /* Event IDs.*/ |
| #include "ia_css_event.h" |
| #include "mmu_device.h" |
| #include "ia_css_spctrl.h" |
| |
| #ifndef offsetof |
| #define offsetof(T, x) ((unsigned)&(((T *)0)->x)) |
| #endif |
| |
| #define IA_CSS_INCLUDE_CONFIGURATIONS |
| #include "ia_css_isp_configs.h" |
| #define IA_CSS_INCLUDE_STATES |
| #include "ia_css_isp_states.h" |
| |
| #ifndef ISP2401 |
| #include "isp/kernels/io_ls/bayer_io_ls/ia_css_bayer_io.host.h" |
| #else |
| #include "isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.h" |
| #endif |
| |
| struct sh_css_sp_group sh_css_sp_group; |
| struct sh_css_sp_stage sh_css_sp_stage; |
| struct sh_css_isp_stage sh_css_isp_stage; |
| struct sh_css_sp_output sh_css_sp_output; |
| static struct sh_css_sp_per_frame_data per_frame_data; |
| |
| /* true if SP supports frame loop and host2sp_commands */ |
| /* For the moment there is only code that sets this bool to true */ |
| /* TODO: add code that sets this bool to false */ |
| static bool sp_running; |
| |
| static enum ia_css_err |
| set_output_frame_buffer(const struct ia_css_frame *frame, |
| unsigned idx); |
| |
| static void |
| sh_css_copy_buffer_attr_to_spbuffer(struct ia_css_buffer_sp *dest_buf, |
| const enum sh_css_queue_id queue_id, |
| const hrt_vaddress xmem_addr, |
| const enum ia_css_buffer_type buf_type); |
| |
| static void |
| initialize_frame_buffer_attribute(struct ia_css_buffer_sp *buf_attr); |
| |
| static void |
| initialize_stage_frames(struct ia_css_frames_sp *frames); |
| |
| /* This data is stored every frame */ |
| void |
| store_sp_group_data(void) |
| { |
| per_frame_data.sp_group_addr = sh_css_store_sp_group_to_ddr(); |
| } |
| |
| static void |
| copy_isp_stage_to_sp_stage(void) |
| { |
| /* [WW07.5]type casting will cause potential issues */ |
| sh_css_sp_stage.num_stripes = (uint8_t) sh_css_isp_stage.binary_info.iterator.num_stripes; |
| sh_css_sp_stage.row_stripes_height = (uint16_t) sh_css_isp_stage.binary_info.iterator.row_stripes_height; |
| sh_css_sp_stage.row_stripes_overlap_lines = (uint16_t) sh_css_isp_stage.binary_info.iterator.row_stripes_overlap_lines; |
| sh_css_sp_stage.top_cropping = (uint16_t) sh_css_isp_stage.binary_info.pipeline.top_cropping; |
| /* moved to sh_css_sp_init_stage |
| sh_css_sp_stage.enable.vf_output = |
| sh_css_isp_stage.binary_info.enable.vf_veceven || |
| sh_css_isp_stage.binary_info.num_output_pins > 1; |
| */ |
| sh_css_sp_stage.enable.sdis = sh_css_isp_stage.binary_info.enable.dis; |
| sh_css_sp_stage.enable.s3a = sh_css_isp_stage.binary_info.enable.s3a; |
| #ifdef ISP2401 |
| sh_css_sp_stage.enable.lace_stats = sh_css_isp_stage.binary_info.enable.lace_stats; |
| #endif |
| } |
| |
| void |
| store_sp_stage_data(enum ia_css_pipe_id id, unsigned int pipe_num, unsigned stage) |
| { |
| unsigned int thread_id; |
| ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); |
| copy_isp_stage_to_sp_stage(); |
| if (id != IA_CSS_PIPE_ID_COPY) |
| sh_css_sp_stage.isp_stage_addr = |
| sh_css_store_isp_stage_to_ddr(pipe_num, stage); |
| sh_css_sp_group.pipe[thread_id].sp_stage_addr[stage] = |
| sh_css_store_sp_stage_to_ddr(pipe_num, stage); |
| |
| /* Clear for next frame */ |
| sh_css_sp_stage.program_input_circuit = false; |
| } |
| |
| static void |
| store_sp_per_frame_data(const struct ia_css_fw_info *fw) |
| { |
| unsigned int HIVE_ADDR_sp_per_frame_data = 0; |
| |
| assert(fw != NULL); |
| |
| switch (fw->type) { |
| case ia_css_sp_firmware: |
| HIVE_ADDR_sp_per_frame_data = fw->info.sp.per_frame_data; |
| break; |
| case ia_css_acc_firmware: |
| HIVE_ADDR_sp_per_frame_data = fw->info.acc.per_frame_data; |
| break; |
| case ia_css_isp_firmware: |
| return; |
| } |
| |
| sp_dmem_store(SP0_ID, |
| (unsigned int)sp_address_of(sp_per_frame_data), |
| &per_frame_data, |
| sizeof(per_frame_data)); |
| } |
| |
| static void |
| sh_css_store_sp_per_frame_data(enum ia_css_pipe_id pipe_id, |
| unsigned int pipe_num, |
| const struct ia_css_fw_info *sp_fw) |
| { |
| if (!sp_fw) |
| sp_fw = &sh_css_sp_fw; |
| |
| store_sp_stage_data(pipe_id, pipe_num, 0); |
| store_sp_group_data(); |
| store_sp_per_frame_data(sp_fw); |
| } |
| |
| #if SP_DEBUG != SP_DEBUG_NONE |
| |
| void |
| sh_css_sp_get_debug_state(struct sh_css_sp_debug_state *state) |
| { |
| const struct ia_css_fw_info *fw = &sh_css_sp_fw; |
| unsigned int HIVE_ADDR_sp_output = fw->info.sp.output; |
| unsigned i; |
| unsigned offset = (unsigned int)offsetof(struct sh_css_sp_output, debug)/sizeof(int); |
| |
| assert(state != NULL); |
| |
| (void)HIVE_ADDR_sp_output; /* To get rid of warning in CRUN */ |
| for (i = 0; i < sizeof(*state)/sizeof(int); i++) |
| ((unsigned *)state)[i] = load_sp_array_uint(sp_output, i+offset); |
| } |
| |
| #endif |
| |
| void |
| sh_css_sp_start_binary_copy(unsigned int pipe_num, struct ia_css_frame *out_frame, |
| unsigned two_ppc) |
| { |
| enum ia_css_pipe_id pipe_id; |
| unsigned int thread_id; |
| struct sh_css_sp_pipeline *pipe; |
| uint8_t stage_num = 0; |
| |
| assert(out_frame != NULL); |
| pipe_id = IA_CSS_PIPE_ID_CAPTURE; |
| ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); |
| pipe = &sh_css_sp_group.pipe[thread_id]; |
| |
| pipe->copy.bin.bytes_available = out_frame->data_bytes; |
| pipe->num_stages = 1; |
| pipe->pipe_id = pipe_id; |
| pipe->pipe_num = pipe_num; |
| pipe->thread_id = thread_id; |
| pipe->pipe_config = 0x0; /* No parameters */ |
| pipe->pipe_qos_config = QOS_INVALID; |
| |
| if (pipe->inout_port_config == 0) { |
| SH_CSS_PIPE_PORT_CONFIG_SET(pipe->inout_port_config, |
| (uint8_t)SH_CSS_PORT_INPUT, |
| (uint8_t)SH_CSS_HOST_TYPE, 1); |
| SH_CSS_PIPE_PORT_CONFIG_SET(pipe->inout_port_config, |
| (uint8_t)SH_CSS_PORT_OUTPUT, |
| (uint8_t)SH_CSS_HOST_TYPE, 1); |
| } |
| IA_CSS_LOG("pipe_id %d port_config %08x", |
| pipe->pipe_id, pipe->inout_port_config); |
| |
| #if !defined(HAS_NO_INPUT_FORMATTER) |
| sh_css_sp_group.config.input_formatter.isp_2ppc = (uint8_t)two_ppc; |
| #else |
| (void)two_ppc; |
| #endif |
| |
| sh_css_sp_stage.num = stage_num; |
| sh_css_sp_stage.stage_type = SH_CSS_SP_STAGE_TYPE; |
| sh_css_sp_stage.func = |
| (unsigned int)IA_CSS_PIPELINE_BIN_COPY; |
| |
| set_output_frame_buffer(out_frame, 0); |
| |
| /* sp_bin_copy_init on the SP does not deal with dynamica/static yet */ |
| /* For now always update the dynamic data from out frames. */ |
| sh_css_store_sp_per_frame_data(pipe_id, pipe_num, &sh_css_sp_fw); |
| } |
| |
| static void |
| sh_css_sp_start_raw_copy(struct ia_css_frame *out_frame, |
| unsigned pipe_num, |
| unsigned two_ppc, |
| unsigned max_input_width, |
| enum sh_css_pipe_config_override pipe_conf_override, |
| unsigned int if_config_index) |
| { |
| enum ia_css_pipe_id pipe_id; |
| unsigned int thread_id; |
| uint8_t stage_num = 0; |
| struct sh_css_sp_pipeline *pipe; |
| |
| assert(out_frame != NULL); |
| |
| { |
| /** |
| * Clear sh_css_sp_stage for easy debugging. |
| * program_input_circuit must be saved as it is set outside |
| * this function. |
| */ |
| uint8_t program_input_circuit; |
| program_input_circuit = sh_css_sp_stage.program_input_circuit; |
| memset(&sh_css_sp_stage, 0, sizeof(sh_css_sp_stage)); |
| sh_css_sp_stage.program_input_circuit = program_input_circuit; |
| } |
| |
| pipe_id = IA_CSS_PIPE_ID_COPY; |
| ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); |
| pipe = &sh_css_sp_group.pipe[thread_id]; |
| |
| pipe->copy.raw.height = out_frame->info.res.height; |
| pipe->copy.raw.width = out_frame->info.res.width; |
| pipe->copy.raw.padded_width = out_frame->info.padded_width; |
| pipe->copy.raw.raw_bit_depth = out_frame->info.raw_bit_depth; |
| pipe->copy.raw.max_input_width = max_input_width; |
| pipe->num_stages = 1; |
| pipe->pipe_id = pipe_id; |
| /* TODO: next indicates from which queues parameters need to be |
| sampled, needs checking/improvement */ |
| if (pipe_conf_override == SH_CSS_PIPE_CONFIG_OVRD_NO_OVRD) |
| pipe->pipe_config = |
| (SH_CSS_PIPE_CONFIG_SAMPLE_PARAMS << thread_id); |
| else |
| pipe->pipe_config = pipe_conf_override; |
| |
| pipe->pipe_qos_config = QOS_INVALID; |
| |
| if (pipe->inout_port_config == 0) { |
| SH_CSS_PIPE_PORT_CONFIG_SET(pipe->inout_port_config, |
| (uint8_t)SH_CSS_PORT_INPUT, |
| (uint8_t)SH_CSS_HOST_TYPE, 1); |
| SH_CSS_PIPE_PORT_CONFIG_SET(pipe->inout_port_config, |
| (uint8_t)SH_CSS_PORT_OUTPUT, |
| (uint8_t)SH_CSS_HOST_TYPE, 1); |
| } |
| IA_CSS_LOG("pipe_id %d port_config %08x", |
| pipe->pipe_id, pipe->inout_port_config); |
| |
| #if !defined(HAS_NO_INPUT_FORMATTER) |
| sh_css_sp_group.config.input_formatter.isp_2ppc = (uint8_t)two_ppc; |
| #else |
| (void)two_ppc; |
| #endif |
| |
| sh_css_sp_stage.num = stage_num; |
| sh_css_sp_stage.xmem_bin_addr = 0x0; |
| sh_css_sp_stage.stage_type = SH_CSS_SP_STAGE_TYPE; |
| sh_css_sp_stage.func = (unsigned int)IA_CSS_PIPELINE_RAW_COPY; |
| sh_css_sp_stage.if_config_index = (uint8_t) if_config_index; |
| set_output_frame_buffer(out_frame, 0); |
| |
| ia_css_debug_pipe_graph_dump_sp_raw_copy(out_frame); |
| } |
| |
| static void |
| sh_css_sp_start_isys_copy(struct ia_css_frame *out_frame, |
| unsigned pipe_num, unsigned max_input_width, unsigned int if_config_index) |
| { |
| enum ia_css_pipe_id pipe_id; |
| unsigned int thread_id; |
| uint8_t stage_num = 0; |
| struct sh_css_sp_pipeline *pipe; |
| #if defined SH_CSS_ENABLE_METADATA |
| enum sh_css_queue_id queue_id; |
| #endif |
| |
| assert(out_frame != NULL); |
| |
| { |
| /** |
| * Clear sh_css_sp_stage for easy debugging. |
| * program_input_circuit must be saved as it is set outside |
| * this function. |
| */ |
| uint8_t program_input_circuit; |
| program_input_circuit = sh_css_sp_stage.program_input_circuit; |
| memset(&sh_css_sp_stage, 0, sizeof(sh_css_sp_stage)); |
| sh_css_sp_stage.program_input_circuit = program_input_circuit; |
| } |
| |
| pipe_id = IA_CSS_PIPE_ID_COPY; |
| ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); |
| pipe = &sh_css_sp_group.pipe[thread_id]; |
| |
| pipe->copy.raw.height = out_frame->info.res.height; |
| pipe->copy.raw.width = out_frame->info.res.width; |
| pipe->copy.raw.padded_width = out_frame->info.padded_width; |
| pipe->copy.raw.raw_bit_depth = out_frame->info.raw_bit_depth; |
| pipe->copy.raw.max_input_width = max_input_width; |
| pipe->num_stages = 1; |
| pipe->pipe_id = pipe_id; |
| pipe->pipe_config = 0x0; /* No parameters */ |
| pipe->pipe_qos_config = QOS_INVALID; |
| |
| initialize_stage_frames(&sh_css_sp_stage.frames); |
| sh_css_sp_stage.num = stage_num; |
| sh_css_sp_stage.xmem_bin_addr = 0x0; |
| sh_css_sp_stage.stage_type = SH_CSS_SP_STAGE_TYPE; |
| sh_css_sp_stage.func = (unsigned int)IA_CSS_PIPELINE_ISYS_COPY; |
| sh_css_sp_stage.if_config_index = (uint8_t) if_config_index; |
| |
| set_output_frame_buffer(out_frame, 0); |
| |
| #if defined SH_CSS_ENABLE_METADATA |
| if (pipe->metadata.height > 0) { |
| ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_METADATA, thread_id, &queue_id); |
| sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.metadata_buf, queue_id, mmgr_EXCEPTION, IA_CSS_BUFFER_TYPE_METADATA); |
| } |
| #endif |
| |
| ia_css_debug_pipe_graph_dump_sp_raw_copy(out_frame); |
| } |
| |
| unsigned int |
| sh_css_sp_get_binary_copy_size(void) |
| { |
| const struct ia_css_fw_info *fw = &sh_css_sp_fw; |
| unsigned int HIVE_ADDR_sp_output = fw->info.sp.output; |
| unsigned int offset = (unsigned int)offsetof(struct sh_css_sp_output, |
| bin_copy_bytes_copied) / sizeof(int); |
| (void)HIVE_ADDR_sp_output; /* To get rid of warning in CRUN */ |
| return load_sp_array_uint(sp_output, offset); |
| } |
| |
| unsigned int |
| sh_css_sp_get_sw_interrupt_value(unsigned int irq) |
| { |
| const struct ia_css_fw_info *fw = &sh_css_sp_fw; |
| unsigned int HIVE_ADDR_sp_output = fw->info.sp.output; |
| unsigned int offset = (unsigned int)offsetof(struct sh_css_sp_output, sw_interrupt_value) |
| / sizeof(int); |
| (void)HIVE_ADDR_sp_output; /* To get rid of warning in CRUN */ |
| return load_sp_array_uint(sp_output, offset+irq); |
| } |
| |
| static void |
| sh_css_copy_buffer_attr_to_spbuffer(struct ia_css_buffer_sp *dest_buf, |
| const enum sh_css_queue_id queue_id, |
| const hrt_vaddress xmem_addr, |
| const enum ia_css_buffer_type buf_type) |
| { |
| assert(buf_type < IA_CSS_NUM_BUFFER_TYPE); |
| if (queue_id > SH_CSS_INVALID_QUEUE_ID) { |
| /* |
| * value >=0 indicates that function init_frame_pointers() |
| * should use the dynamic data address |
| */ |
| assert(queue_id < SH_CSS_MAX_NUM_QUEUES); |
| |
| /* Klocwork assumes assert can be disabled; |
| Since we can get there with any type, and it does not |
| know that frame_in->dynamic_data_index can only be set |
| for one of the types in the assert) it has to assume we |
| can get here for any type. however this could lead to an |
| out of bounds reference when indexing buf_type about 10 |
| lines below. In order to satisfy KW an additional if |
| has been added. This one will always yield true. |
| */ |
| if ((queue_id < SH_CSS_MAX_NUM_QUEUES)) |
| { |
| dest_buf->buf_src.queue_id = queue_id; |
| } |
| } else { |
| assert(xmem_addr != mmgr_EXCEPTION); |
| dest_buf->buf_src.xmem_addr = xmem_addr; |
| } |
| dest_buf->buf_type = buf_type; |
| } |
| |
| static void |
| sh_css_copy_frame_to_spframe(struct ia_css_frame_sp *sp_frame_out, |
| const struct ia_css_frame *frame_in) |
| { |
| assert(frame_in != NULL); |
| |
| ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, |
| "sh_css_copy_frame_to_spframe():\n"); |
| |
| |
| sh_css_copy_buffer_attr_to_spbuffer(&sp_frame_out->buf_attr, |
| frame_in->dynamic_queue_id, |
| frame_in->data, |
| frame_in->buf_type); |
| |
| ia_css_frame_info_to_frame_sp_info(&sp_frame_out->info, &frame_in->info); |
| |
| switch (frame_in->info.format) { |
| case IA_CSS_FRAME_FORMAT_RAW_PACKED: |
| case IA_CSS_FRAME_FORMAT_RAW: |
| sp_frame_out->planes.raw.offset = frame_in->planes.raw.offset; |
| break; |
| case IA_CSS_FRAME_FORMAT_RGB565: |
| case IA_CSS_FRAME_FORMAT_RGBA888: |
| sp_frame_out->planes.rgb.offset = frame_in->planes.rgb.offset; |
| break; |
| case IA_CSS_FRAME_FORMAT_PLANAR_RGB888: |
| sp_frame_out->planes.planar_rgb.r.offset = |
| frame_in->planes.planar_rgb.r.offset; |
| sp_frame_out->planes.planar_rgb.g.offset = |
| frame_in->planes.planar_rgb.g.offset; |
| sp_frame_out->planes.planar_rgb.b.offset = |
| frame_in->planes.planar_rgb.b.offset; |
| break; |
| case IA_CSS_FRAME_FORMAT_YUYV: |
| case IA_CSS_FRAME_FORMAT_UYVY: |
| case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8: |
| case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8: |
| case IA_CSS_FRAME_FORMAT_YUV_LINE: |
| sp_frame_out->planes.yuyv.offset = frame_in->planes.yuyv.offset; |
| break; |
| case IA_CSS_FRAME_FORMAT_NV11: |
| case IA_CSS_FRAME_FORMAT_NV12: |
| case IA_CSS_FRAME_FORMAT_NV12_16: |
| case IA_CSS_FRAME_FORMAT_NV12_TILEY: |
| case IA_CSS_FRAME_FORMAT_NV21: |
| case IA_CSS_FRAME_FORMAT_NV16: |
| case IA_CSS_FRAME_FORMAT_NV61: |
| sp_frame_out->planes.nv.y.offset = |
| frame_in->planes.nv.y.offset; |
| sp_frame_out->planes.nv.uv.offset = |
| frame_in->planes.nv.uv.offset; |
| break; |
| case IA_CSS_FRAME_FORMAT_YUV420: |
| case IA_CSS_FRAME_FORMAT_YUV422: |
| case IA_CSS_FRAME_FORMAT_YUV444: |
| case IA_CSS_FRAME_FORMAT_YUV420_16: |
| case IA_CSS_FRAME_FORMAT_YUV422_16: |
| case IA_CSS_FRAME_FORMAT_YV12: |
| case IA_CSS_FRAME_FORMAT_YV16: |
| sp_frame_out->planes.yuv.y.offset = |
| frame_in->planes.yuv.y.offset; |
| sp_frame_out->planes.yuv.u.offset = |
| frame_in->planes.yuv.u.offset; |
| sp_frame_out->planes.yuv.v.offset = |
| frame_in->planes.yuv.v.offset; |
| break; |
| case IA_CSS_FRAME_FORMAT_QPLANE6: |
| sp_frame_out->planes.plane6.r.offset = |
| frame_in->planes.plane6.r.offset; |
| sp_frame_out->planes.plane6.r_at_b.offset = |
| frame_in->planes.plane6.r_at_b.offset; |
| sp_frame_out->planes.plane6.gr.offset = |
| frame_in->planes.plane6.gr.offset; |
| sp_frame_out->planes.plane6.gb.offset = |
| frame_in->planes.plane6.gb.offset; |
| sp_frame_out->planes.plane6.b.offset = |
| frame_in->planes.plane6.b.offset; |
| sp_frame_out->planes.plane6.b_at_r.offset = |
| frame_in->planes.plane6.b_at_r.offset; |
| break; |
| case IA_CSS_FRAME_FORMAT_BINARY_8: |
| sp_frame_out->planes.binary.data.offset = |
| frame_in->planes.binary.data.offset; |
| break; |
| default: |
| /* This should not happen, but in case it does, |
| * nullify the planes |
| */ |
| memset(&sp_frame_out->planes, 0, sizeof(sp_frame_out->planes)); |
| break; |
| } |
| |
| } |
| |
| static enum ia_css_err |
| set_input_frame_buffer(const struct ia_css_frame *frame) |
| { |
| if (frame == NULL) |
| return IA_CSS_ERR_INVALID_ARGUMENTS; |
| |
| switch (frame->info.format) { |
| case IA_CSS_FRAME_FORMAT_QPLANE6: |
| case IA_CSS_FRAME_FORMAT_YUV420_16: |
| case IA_CSS_FRAME_FORMAT_RAW_PACKED: |
| case IA_CSS_FRAME_FORMAT_RAW: |
| case IA_CSS_FRAME_FORMAT_YUV420: |
| case IA_CSS_FRAME_FORMAT_YUYV: |
| case IA_CSS_FRAME_FORMAT_YUV_LINE: |
| case IA_CSS_FRAME_FORMAT_NV12: |
| case IA_CSS_FRAME_FORMAT_NV12_16: |
| case IA_CSS_FRAME_FORMAT_NV12_TILEY: |
| case IA_CSS_FRAME_FORMAT_NV21: |
| case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8: |
| case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8: |
| case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_10: |
| break; |
| default: |
| return IA_CSS_ERR_INVALID_ARGUMENTS; |
| } |
| sh_css_copy_frame_to_spframe(&sh_css_sp_stage.frames.in, frame); |
| |
| return IA_CSS_SUCCESS; |
| } |
| |
| static enum ia_css_err |
| set_output_frame_buffer(const struct ia_css_frame *frame, |
| unsigned idx) |
| { |
| if (frame == NULL) |
| return IA_CSS_ERR_INVALID_ARGUMENTS; |
| |
| switch (frame->info.format) { |
| case IA_CSS_FRAME_FORMAT_YUV420: |
| case IA_CSS_FRAME_FORMAT_YUV422: |
| case IA_CSS_FRAME_FORMAT_YUV444: |
| case IA_CSS_FRAME_FORMAT_YV12: |
| case IA_CSS_FRAME_FORMAT_YV16: |
| case IA_CSS_FRAME_FORMAT_YUV420_16: |
| case IA_CSS_FRAME_FORMAT_YUV422_16: |
| case IA_CSS_FRAME_FORMAT_NV11: |
| case IA_CSS_FRAME_FORMAT_NV12: |
| case IA_CSS_FRAME_FORMAT_NV12_16: |
| case IA_CSS_FRAME_FORMAT_NV12_TILEY: |
| case IA_CSS_FRAME_FORMAT_NV16: |
| case IA_CSS_FRAME_FORMAT_NV21: |
| case IA_CSS_FRAME_FORMAT_NV61: |
| case IA_CSS_FRAME_FORMAT_YUYV: |
| case IA_CSS_FRAME_FORMAT_UYVY: |
| case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8: |
| case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8: |
| case IA_CSS_FRAME_FORMAT_YUV_LINE: |
| case IA_CSS_FRAME_FORMAT_RGB565: |
| case IA_CSS_FRAME_FORMAT_RGBA888: |
| case IA_CSS_FRAME_FORMAT_PLANAR_RGB888: |
| case IA_CSS_FRAME_FORMAT_RAW: |
| case IA_CSS_FRAME_FORMAT_RAW_PACKED: |
| case IA_CSS_FRAME_FORMAT_QPLANE6: |
| case IA_CSS_FRAME_FORMAT_BINARY_8: |
| break; |
| default: |
| return IA_CSS_ERR_INVALID_ARGUMENTS; |
| } |
| sh_css_copy_frame_to_spframe(&sh_css_sp_stage.frames.out[idx], frame); |
| return IA_CSS_SUCCESS; |
| } |
| |
| static enum ia_css_err |
| set_view_finder_buffer(const struct ia_css_frame *frame) |
| { |
| if (frame == NULL) |
| return IA_CSS_ERR_INVALID_ARGUMENTS; |
| |
| switch (frame->info.format) { |
| /* the dual output pin */ |
| case IA_CSS_FRAME_FORMAT_NV12: |
| case IA_CSS_FRAME_FORMAT_NV12_16: |
| case IA_CSS_FRAME_FORMAT_NV21: |
| case IA_CSS_FRAME_FORMAT_YUYV: |
| case IA_CSS_FRAME_FORMAT_UYVY: |
| case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8: |
| case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8: |
| case IA_CSS_FRAME_FORMAT_YUV420: |
| case IA_CSS_FRAME_FORMAT_YV12: |
| case IA_CSS_FRAME_FORMAT_NV12_TILEY: |
| |
| /* for vf_veceven */ |
| case IA_CSS_FRAME_FORMAT_YUV_LINE: |
| break; |
| default: |
| return IA_CSS_ERR_INVALID_ARGUMENTS; |
| } |
| |
| sh_css_copy_frame_to_spframe(&sh_css_sp_stage.frames.out_vf, frame); |
| return IA_CSS_SUCCESS; |
| } |
| |
| #if !defined(HAS_NO_INPUT_FORMATTER) |
| void sh_css_sp_set_if_configs( |
| const input_formatter_cfg_t *config_a, |
| const input_formatter_cfg_t *config_b, |
| const uint8_t if_config_index |
| ) |
| { |
| assert(if_config_index < SH_CSS_MAX_IF_CONFIGS); |
| assert(config_a != NULL); |
| |
| sh_css_sp_group.config.input_formatter.set[if_config_index].config_a = *config_a; |
| sh_css_sp_group.config.input_formatter.a_changed = true; |
| |
| if (config_b != NULL) { |
| sh_css_sp_group.config.input_formatter.set[if_config_index].config_b = *config_b; |
| sh_css_sp_group.config.input_formatter.b_changed = true; |
| } |
| |
| return; |
| } |
| #endif |
| |
| #if !defined(HAS_NO_INPUT_SYSTEM) && defined(USE_INPUT_SYSTEM_VERSION_2) |
| void |
| sh_css_sp_program_input_circuit(int fmt_type, |
| int ch_id, |
| enum ia_css_input_mode input_mode) |
| { |
| sh_css_sp_group.config.input_circuit.no_side_band = false; |
| sh_css_sp_group.config.input_circuit.fmt_type = fmt_type; |
| sh_css_sp_group.config.input_circuit.ch_id = ch_id; |
| sh_css_sp_group.config.input_circuit.input_mode = input_mode; |
| /* |
| * The SP group is only loaded at SP boot time and is read once |
| * change flags as "input_circuit_cfg_changed" must be reset on the SP |
| */ |
| sh_css_sp_group.config.input_circuit_cfg_changed = true; |
| sh_css_sp_stage.program_input_circuit = true; |
| } |
| #endif |
| |
| #if !defined(HAS_NO_INPUT_SYSTEM) && defined(USE_INPUT_SYSTEM_VERSION_2) |
| void |
| sh_css_sp_configure_sync_gen(int width, int height, |
| int hblank_cycles, |
| int vblank_cycles) |
| { |
| sh_css_sp_group.config.sync_gen.width = width; |
| sh_css_sp_group.config.sync_gen.height = height; |
| sh_css_sp_group.config.sync_gen.hblank_cycles = hblank_cycles; |
| sh_css_sp_group.config.sync_gen.vblank_cycles = vblank_cycles; |
| } |
| |
| void |
| sh_css_sp_configure_tpg(int x_mask, |
| int y_mask, |
| int x_delta, |
| int y_delta, |
| int xy_mask) |
| { |
| sh_css_sp_group.config.tpg.x_mask = x_mask; |
| sh_css_sp_group.config.tpg.y_mask = y_mask; |
| sh_css_sp_group.config.tpg.x_delta = x_delta; |
| sh_css_sp_group.config.tpg.y_delta = y_delta; |
| sh_css_sp_group.config.tpg.xy_mask = xy_mask; |
| } |
| |
| void |
| sh_css_sp_configure_prbs(int seed) |
| { |
| sh_css_sp_group.config.prbs.seed = seed; |
| } |
| #endif |
| |
| void |
| sh_css_sp_configure_enable_raw_pool_locking(bool lock_all) |
| { |
| sh_css_sp_group.config.enable_raw_pool_locking = true; |
| sh_css_sp_group.config.lock_all = lock_all; |
| } |
| |
| void |
| sh_css_sp_enable_isys_event_queue(bool enable) |
| { |
| #if !defined(HAS_NO_INPUT_SYSTEM) |
| sh_css_sp_group.config.enable_isys_event_queue = enable; |
| #else |
| (void)enable; |
| #endif |
| } |
| |
| void |
| sh_css_sp_set_disable_continuous_viewfinder(bool flag) |
| { |
| sh_css_sp_group.config.disable_cont_vf = flag; |
| } |
| |
| static enum ia_css_err |
| sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) |
| { |
| enum ia_css_err err = IA_CSS_SUCCESS; |
| int i; |
| |
| assert(args != NULL); |
| |
| if (args->in_frame) |
| err = set_input_frame_buffer(args->in_frame); |
| if (err == IA_CSS_SUCCESS && args->out_vf_frame) |
| err = set_view_finder_buffer(args->out_vf_frame); |
| for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { |
| if (err == IA_CSS_SUCCESS && args->out_frame[i]) |
| err = set_output_frame_buffer(args->out_frame[i], i); |
| } |
| |
| /* we don't pass this error back to the upper layer, so we add a assert here |
| because we actually hit the error here but it still works by accident... */ |
| if (err != IA_CSS_SUCCESS) assert(false); |
| return err; |
| } |
| |
| static void |
| sh_css_sp_init_group(bool two_ppc, |
| enum ia_css_stream_format input_format, |
| bool no_isp_sync, |
| uint8_t if_config_index) |
| { |
| #if !defined(HAS_NO_INPUT_FORMATTER) |
| sh_css_sp_group.config.input_formatter.isp_2ppc = two_ppc; |
| #else |
| (void)two_ppc; |
| #endif |
| |
| sh_css_sp_group.config.no_isp_sync = (uint8_t)no_isp_sync; |
| /* decide whether the frame is processed online or offline */ |
| if (if_config_index == SH_CSS_IF_CONFIG_NOT_NEEDED) return; |
| #if !defined(HAS_NO_INPUT_FORMATTER) |
| assert(if_config_index < SH_CSS_MAX_IF_CONFIGS); |
| sh_css_sp_group.config.input_formatter.set[if_config_index].stream_format = input_format; |
| #else |
| (void)input_format; |
| #endif |
| } |
| |
| void |
| sh_css_stage_write_binary_info(struct ia_css_binary_info *info) |
| { |
| assert(info != NULL); |
| sh_css_isp_stage.binary_info = *info; |
| } |
| |
| static enum ia_css_err |
| copy_isp_mem_if_to_ddr(struct ia_css_binary *binary) |
| { |
| enum ia_css_err err; |
| |
| err = ia_css_isp_param_copy_isp_mem_if_to_ddr( |
| &binary->css_params, |
| &binary->mem_params, |
| IA_CSS_PARAM_CLASS_CONFIG); |
| if (err != IA_CSS_SUCCESS) |
| return err; |
| err = ia_css_isp_param_copy_isp_mem_if_to_ddr( |
| &binary->css_params, |
| &binary->mem_params, |
| IA_CSS_PARAM_CLASS_STATE); |
| if (err != IA_CSS_SUCCESS) |
| return err; |
| return IA_CSS_SUCCESS; |
| } |
| |
| static bool |
| is_sp_stage(struct ia_css_pipeline_stage *stage) |
| { |
| assert(stage != NULL); |
| return stage->sp_func != IA_CSS_PIPELINE_NO_FUNC; |
| } |
| |
| static enum ia_css_err |
| configure_isp_from_args( |
| const struct sh_css_sp_pipeline *pipeline, |
| const struct ia_css_binary *binary, |
| const struct sh_css_binary_args *args, |
| bool two_ppc, |
| bool deinterleaved) |
| { |
| enum ia_css_err err = IA_CSS_SUCCESS; |
| #ifdef ISP2401 |
| struct ia_css_pipe *pipe = find_pipe_by_num(pipeline->pipe_num); |
| const struct ia_css_resolution *res; |
| |
| #endif |
| ia_css_fpn_configure(binary, &binary->in_frame_info); |
| ia_css_crop_configure(binary, &args->delay_frames[0]->info); |
| ia_css_qplane_configure(pipeline, binary, &binary->in_frame_info); |
| ia_css_output0_configure(binary, &args->out_frame[0]->info); |
| ia_css_output1_configure(binary, &args->out_vf_frame->info); |
| ia_css_copy_output_configure(binary, args->copy_output); |
| ia_css_output0_configure(binary, &args->out_frame[0]->info); |
| #ifdef ISP2401 |
| ia_css_sc_configure(binary, pipeline->shading.internal_frame_origin_x_bqs_on_sctbl, |
| pipeline->shading.internal_frame_origin_y_bqs_on_sctbl); |
| #endif |
| ia_css_iterator_configure(binary, &args->in_frame->info); |
| ia_css_dvs_configure(binary, &args->out_frame[0]->info); |
| ia_css_output_configure(binary, &args->out_frame[0]->info); |
| ia_css_raw_configure(pipeline, binary, &args->in_frame->info, &binary->in_frame_info, two_ppc, deinterleaved); |
| ia_css_ref_configure(binary, (const struct ia_css_frame **)args->delay_frames, pipeline->dvs_frame_delay); |
| ia_css_tnr_configure(binary, (const struct ia_css_frame **)args->tnr_frames); |
| ia_css_bayer_io_config(binary, args); |
| return err; |
| } |
| |
| static void |
| initialize_isp_states(const struct ia_css_binary *binary) |
| { |
| unsigned int i; |
| |
| if (!binary->info->mem_offsets.offsets.state) |
| return; |
| for (i = 0; i < IA_CSS_NUM_STATE_IDS; i++) { |
| ia_css_kernel_init_state[i](binary); |
| } |
| } |
| |
| static void |
| initialize_frame_buffer_attribute(struct ia_css_buffer_sp *buf_attr) |
| { |
| buf_attr->buf_src.queue_id = SH_CSS_INVALID_QUEUE_ID; |
| buf_attr->buf_type = IA_CSS_BUFFER_TYPE_INVALID; |
| } |
| |
| static void |
| initialize_stage_frames(struct ia_css_frames_sp *frames) |
| { |
| unsigned int i; |
| |
| initialize_frame_buffer_attribute(&frames->in.buf_attr); |
| for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { |
| initialize_frame_buffer_attribute(&frames->out[i].buf_attr); |
| } |
| initialize_frame_buffer_attribute(&frames->out_vf.buf_attr); |
| initialize_frame_buffer_attribute(&frames->s3a_buf); |
| initialize_frame_buffer_attribute(&frames->dvs_buf); |
| #if defined SH_CSS_ENABLE_METADATA |
| initialize_frame_buffer_attribute(&frames->metadata_buf); |
| #endif |
| } |
| |
| static enum ia_css_err |
| sh_css_sp_init_stage(struct ia_css_binary *binary, |
| const char *binary_name, |
| const struct ia_css_blob_info *blob_info, |
| const struct sh_css_binary_args *args, |
| unsigned int pipe_num, |
| unsigned stage, |
| bool xnr, |
| const struct ia_css_isp_param_css_segments *isp_mem_if, |
| unsigned int if_config_index, |
| bool two_ppc) |
| { |
| const struct ia_css_binary_xinfo *xinfo; |
| const struct ia_css_binary_info *info; |
| enum ia_css_err err = IA_CSS_SUCCESS; |
| int i; |
| struct ia_css_pipe *pipe = NULL; |
| unsigned int thread_id; |
| enum sh_css_queue_id queue_id; |
| bool continuous = sh_css_continuous_is_enabled((uint8_t)pipe_num); |
| |
| assert(binary != NULL); |
| assert(blob_info != NULL); |
| assert(args != NULL); |
| assert(isp_mem_if != NULL); |
| |
| xinfo = binary->info; |
| info = &xinfo->sp; |
| { |
| /** |
| * Clear sh_css_sp_stage for easy debugging. |
| * program_input_circuit must be saved as it is set outside |
| * this function. |
| */ |
| uint8_t program_input_circuit; |
| program_input_circuit = sh_css_sp_stage.program_input_circuit; |
| memset(&sh_css_sp_stage, 0, sizeof(sh_css_sp_stage)); |
| sh_css_sp_stage.program_input_circuit = (uint8_t)program_input_circuit; |
| } |
| |
| ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); |
| |
| if (info == NULL) { |
| sh_css_sp_group.pipe[thread_id].sp_stage_addr[stage] = mmgr_NULL; |
| return IA_CSS_SUCCESS; |
| } |
| |
| #if defined(USE_INPUT_SYSTEM_VERSION_2401) |
| (void)continuous; |
| sh_css_sp_stage.deinterleaved = 0; |
| #else |
| sh_css_sp_stage.deinterleaved = ((stage == 0) && continuous); |
| #endif |
| |
| initialize_stage_frames(&sh_css_sp_stage.frames); |
| /* |
| * TODO: Make the Host dynamically determine |
| * the stage type. |
| */ |
| sh_css_sp_stage.stage_type = SH_CSS_ISP_STAGE_TYPE; |
| sh_css_sp_stage.num = (uint8_t)stage; |
| sh_css_sp_stage.isp_online = (uint8_t)binary->online; |
| sh_css_sp_stage.isp_copy_vf = (uint8_t)args->copy_vf; |
| sh_css_sp_stage.isp_copy_output = (uint8_t)args->copy_output; |
| sh_css_sp_stage.enable.vf_output = (args->out_vf_frame != NULL); |
| |
| /* Copy the frame infos first, to be overwritten by the frames, |
| if these are present. |
| */ |
| sh_css_sp_stage.frames.effective_in_res.width = binary->effective_in_frame_res.width; |
| sh_css_sp_stage.frames.effective_in_res.height = binary->effective_in_frame_res.height; |
| |
| ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.in.info, |
| &binary->in_frame_info); |
| for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { |
| ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.out[i].info, |
| &binary->out_frame_info[i]); |
| } |
| ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.internal_frame_info, |
| &binary->internal_frame_info); |
| sh_css_sp_stage.dvs_envelope.width = binary->dvs_envelope.width; |
| sh_css_sp_stage.dvs_envelope.height = binary->dvs_envelope.height; |
| sh_css_sp_stage.isp_pipe_version = (uint8_t)info->pipeline.isp_pipe_version; |
| sh_css_sp_stage.isp_deci_log_factor = (uint8_t)binary->deci_factor_log2; |
| sh_css_sp_stage.isp_vf_downscale_bits = (uint8_t)binary->vf_downscale_log2; |
| |
| sh_css_sp_stage.if_config_index = (uint8_t) if_config_index; |
| |
| sh_css_sp_stage.sp_enable_xnr = (uint8_t)xnr; |
| sh_css_sp_stage.xmem_bin_addr = xinfo->xmem_addr; |
| sh_css_sp_stage.xmem_map_addr = sh_css_params_ddr_address_map(); |
| sh_css_isp_stage.blob_info = *blob_info; |
| sh_css_stage_write_binary_info((struct ia_css_binary_info *)info); |
| |
| /* Make sure binary name is smaller than allowed string size */ |
| assert(strlen(binary_name) < SH_CSS_MAX_BINARY_NAME-1); |
| strncpy(sh_css_isp_stage.binary_name, binary_name, SH_CSS_MAX_BINARY_NAME-1); |
| sh_css_isp_stage.binary_name[SH_CSS_MAX_BINARY_NAME - 1] = 0; |
| sh_css_isp_stage.mem_initializers = *isp_mem_if; |
| |
| /** |
| * Even when a stage does not need uds and does not params, |
| * ia_css_uds_sp_scale_params() seems to be called (needs |
| * further investigation). This function can not deal with |
| * dx, dy = {0, 0} |
| */ |
| |
| err = sh_css_sp_write_frame_pointers(args); |
| /* TODO: move it to a better place */ |
| if (binary->info->sp.enable.s3a) { |
| ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_3A_STATISTICS, thread_id, &queue_id); |
| sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.s3a_buf, queue_id, mmgr_EXCEPTION, IA_CSS_BUFFER_TYPE_3A_STATISTICS); |
| } |
| if (binary->info->sp.enable.dis) { |
| ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_DIS_STATISTICS, thread_id, &queue_id); |
| sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.dvs_buf, queue_id, mmgr_EXCEPTION, IA_CSS_BUFFER_TYPE_DIS_STATISTICS); |
| } |
| #if defined SH_CSS_ENABLE_METADATA |
| ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_METADATA, thread_id, &queue_id); |
| sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.metadata_buf, queue_id, mmgr_EXCEPTION, IA_CSS_BUFFER_TYPE_METADATA); |
| #endif |
| if (err != IA_CSS_SUCCESS) |
| return err; |
| |
| #ifdef USE_INPUT_SYSTEM_VERSION_2401 |
| #ifndef ISP2401 |
| if (args->in_frame) { |
| pipe = find_pipe_by_num(sh_css_sp_group.pipe[thread_id].pipe_num); |
| if (pipe == NULL) |
| return IA_CSS_ERR_INTERNAL_ERROR; |
| ia_css_get_crop_offsets(pipe, &args->in_frame->info); |
| } else if (&binary->in_frame_info) { |
| pipe = find_pipe_by_num(sh_css_sp_group.pipe[thread_id].pipe_num); |
| if (pipe == NULL) |
| return IA_CSS_ERR_INTERNAL_ERROR; |
| ia_css_get_crop_offsets(pipe, &binary->in_frame_info); |
| #else |
| if (stage == 0) { |
| if (args->in_frame) { |
| pipe = find_pipe_by_num(sh_css_sp_group.pipe[thread_id].pipe_num); |
| if (pipe == NULL) |
| return IA_CSS_ERR_INTERNAL_ERROR; |
| ia_css_get_crop_offsets(pipe, &args->in_frame->info); |
| } else if (&binary->in_frame_info) { |
| pipe = find_pipe_by_num(sh_css_sp_group.pipe[thread_id].pipe_num); |
| if (pipe == NULL) |
| return IA_CSS_ERR_INTERNAL_ERROR; |
| ia_css_get_crop_offsets(pipe, &binary->in_frame_info); |
| } |
| #endif |
| } |
| #else |
| (void)pipe; /*avoid build warning*/ |
| #endif |
| |
| err = configure_isp_from_args(&sh_css_sp_group.pipe[thread_id], |
| binary, args, two_ppc, sh_css_sp_stage.deinterleaved); |
| if (err != IA_CSS_SUCCESS) |
| return err; |
| |
| initialize_isp_states(binary); |
| |
| /* we do this only for preview pipe because in fill_binary_info function |
| * we assign vf_out res to out res, but for ISP internal processing, we need |
| * the original out res. for video pipe, it has two output pins --- out and |
| * vf_out, so it can keep these two resolutions already. */ |
| if (binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_PREVIEW && |
| (binary->vf_downscale_log2 > 0)) { |
| /* TODO: Remove this after preview output decimation is fixed |
| * by configuring out&vf info fiels properly */ |
| sh_css_sp_stage.frames.out[0].info.padded_width |
| <<= binary->vf_downscale_log2; |
| sh_css_sp_stage.frames.out[0].info.res.width |
| <<= binary->vf_downscale_log2; |
| sh_css_sp_stage.frames.out[0].info.res.height |
| <<= binary->vf_downscale_log2; |
| } |
| err = copy_isp_mem_if_to_ddr(binary); |
| if (err != IA_CSS_SUCCESS) |
| return err; |
| |
| return IA_CSS_SUCCESS; |
| } |
| |
| static enum ia_css_err |
| sp_init_stage(struct ia_css_pipeline_stage *stage, |
| unsigned int pipe_num, |
| bool xnr, |
| unsigned int if_config_index, |
| bool two_ppc) |
| { |
| struct ia_css_binary *binary; |
| const struct ia_css_fw_info *firmware; |
| const struct sh_css_binary_args *args; |
| unsigned stage_num; |
| /* |
| * Initialiser required because of the "else" path below. |
| * Is this a valid path ? |
| */ |
| const char *binary_name = ""; |
| const struct ia_css_binary_xinfo *info = NULL; |
| /* note: the var below is made static as it is quite large; |
| if it is not static it ends up on the stack which could |
| cause issues for drivers |
| */ |
| static struct ia_css_binary tmp_binary; |
| const struct ia_css_blob_info *blob_info = NULL; |
| struct ia_css_isp_param_css_segments isp_mem_if; |
| /* LA: should be ia_css_data, should not contain host pointer. |
| However, CSS/DDR pointer is not available yet. |
| Hack is to store it in params->ddr_ptrs and then copy it late in the SP just before vmem init. |
| TODO: Call this after CSS/DDR allocation and store that pointer. |
| Best is to allocate it at stage creation time together with host pointer. |
| Remove vmem from params. |
| */ |
| struct ia_css_isp_param_css_segments *mem_if = &isp_mem_if; |
| |
| enum ia_css_err err = IA_CSS_SUCCESS; |
| |
| assert(stage != NULL); |
| |
| binary = stage->binary; |
| firmware = stage->firmware; |
| args = &stage->args; |
| stage_num = stage->stage_num; |
| |
| |
| if (binary) { |
| info = binary->info; |
| binary_name = (const char *)(info->blob->name); |
| blob_info = &info->blob->header.blob; |
| ia_css_init_memory_interface(mem_if, &binary->mem_params, &binary->css_params); |
| } else if (firmware) { |
| const struct ia_css_frame_info *out_infos[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL}; |
| if (args->out_frame[0]) |
| out_infos[0] = &args->out_frame[0]->info; |
| info = &firmware->info.isp; |
| ia_css_binary_fill_info(info, false, false, |
| IA_CSS_STREAM_FORMAT_RAW_10, |
| args->in_frame ? &args->in_frame->info : NULL, |
| NULL, |
| out_infos, |
| args->out_vf_frame ? &args->out_vf_frame->info |
| : NULL, |
| &tmp_binary, |
| NULL, |
| -1, true); |
| binary = &tmp_binary; |
| binary->info = info; |
| binary_name = IA_CSS_EXT_ISP_PROG_NAME(firmware); |
| blob_info = &firmware->blob; |
| mem_if = (struct ia_css_isp_param_css_segments *)&firmware->mem_initializers; |
| } else { |
| /* SP stage */ |
| assert(stage->sp_func != IA_CSS_PIPELINE_NO_FUNC); |
| /* binary and blob_info are now NULL. |
| These will be passed to sh_css_sp_init_stage |
| and dereferenced there, so passing a NULL |
| pointer is no good. return an error */ |
| return IA_CSS_ERR_INTERNAL_ERROR; |
| } |
| |
| err = sh_css_sp_init_stage(binary, |
| (const char *)binary_name, |
| blob_info, |
| args, |
| pipe_num, |
| stage_num, |
| xnr, |
| mem_if, |
| if_config_index, |
| two_ppc); |
| return err; |
| } |
| |
| static void |
| sp_init_sp_stage(struct ia_css_pipeline_stage *stage, |
| unsigned pipe_num, |
| bool two_ppc, |
| enum sh_css_pipe_config_override copy_ovrd, |
| unsigned int if_config_index) |
| { |
| const struct sh_css_binary_args *args = &stage->args; |
| |
| assert(stage != NULL); |
| switch (stage->sp_func) { |
| case IA_CSS_PIPELINE_RAW_COPY: |
| sh_css_sp_start_raw_copy(args->out_frame[0], |
| pipe_num, two_ppc, |
| stage->max_input_width, |
| copy_ovrd, if_config_index); |
| break; |
| case IA_CSS_PIPELINE_BIN_COPY: |
| assert(false); /* TBI */ |
| case IA_CSS_PIPELINE_ISYS_COPY: |
| sh_css_sp_start_isys_copy(args->out_frame[0], |
| pipe_num, stage->max_input_width, if_config_index); |
| break; |
| case IA_CSS_PIPELINE_NO_FUNC: |
| assert(false); |
| } |
| } |
| |
| void |
| sh_css_sp_init_pipeline(struct ia_css_pipeline *me, |
| enum ia_css_pipe_id id, |
| uint8_t pipe_num, |
| bool xnr, |
| bool two_ppc, |
| bool continuous, |
| bool offline, |
| unsigned int required_bds_factor, |
| enum sh_css_pipe_config_override copy_ovrd, |
| enum ia_css_input_mode input_mode, |
| const struct ia_css_metadata_config *md_config, |
| const struct ia_css_metadata_info *md_info, |
| #if !defined(HAS_NO_INPUT_SYSTEM) |
| const mipi_port_ID_t port_id |
| #endif |
| #ifdef ISP2401 |
| , |
| const struct ia_css_coordinate *internal_frame_origin_bqs_on_sctbl, /* Origin of internal frame |
| positioned on shading table at shading correction in ISP. */ |
| const struct ia_css_isp_parameters *params |
| #endif |
| ) |
| { |
| /* Get first stage */ |
| struct ia_css_pipeline_stage *stage = NULL; |
| struct ia_css_binary *first_binary = NULL; |
| struct ia_css_pipe *pipe = NULL; |
| unsigned num; |
| |
| enum ia_css_pipe_id pipe_id = id; |
| unsigned int thread_id; |
| uint8_t if_config_index, tmp_if_config_index; |
| |
| assert(me != NULL); |
| |
| #if !defined(HAS_NO_INPUT_SYSTEM) |
| assert(me->stages != NULL); |
| |
| first_binary = me->stages->binary; |
| |
| if (input_mode == IA_CSS_INPUT_MODE_SENSOR || |
| input_mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { |
| assert(port_id < N_MIPI_PORT_ID); |
| if (port_id >= N_MIPI_PORT_ID) /* should not happen but KW does not know */ |
| return; /* we should be able to return an error */ |
| if_config_index = (uint8_t) (port_id - MIPI_PORT0_ID); |
| } else if (input_mode == IA_CSS_INPUT_MODE_MEMORY) { |
| if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED; |
| } else { |
| if_config_index = 0x0; |
| } |
| #else |
| (void)input_mode; |
| if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED; |
| #endif |
| |
| ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); |
| memset(&sh_css_sp_group.pipe[thread_id], 0, sizeof(struct sh_css_sp_pipeline)); |
| |
| /* Count stages */ |
| for (stage = me->stages, num = 0; stage; stage = stage->next, num++) { |
| stage->stage_num = num; |
| ia_css_debug_pipe_graph_dump_stage(stage, id); |
| } |
| me->num_stages = num; |
| |
| if (first_binary != NULL) { |
| /* Init pipeline data */ |
| sh_css_sp_init_group(two_ppc, first_binary->input_format, |
| offline, if_config_index); |
| } /* if (first_binary != NULL) */ |
| |
| #if defined(USE_INPUT_SYSTEM_VERSION_2401) || defined(USE_INPUT_SYSTEM_VERSION_2) |
| /* Signal the host immediately after start for SP_ISYS_COPY only */ |
| if ((me->num_stages == 1) && me->stages && |
| (me->stages->sp_func == IA_CSS_PIPELINE_ISYS_COPY)) |
| sh_css_sp_group.config.no_isp_sync = true; |
| #endif |
| |
| /* Init stage data */ |
| sh_css_init_host2sp_frame_data(); |
| |
| sh_css_sp_group.pipe[thread_id].num_stages = 0; |
| sh_css_sp_group.pipe[thread_id].pipe_id = pipe_id; |
| sh_css_sp_group.pipe[thread_id].thread_id = thread_id; |
| sh_css_sp_group.pipe[thread_id].pipe_num = pipe_num; |
| sh_css_sp_group.pipe[thread_id].num_execs = me->num_execs; |
| sh_css_sp_group.pipe[thread_id].pipe_qos_config = me->pipe_qos_config; |
| sh_css_sp_group.pipe[thread_id].required_bds_factor = required_bds_factor; |
| #if !defined(HAS_NO_INPUT_SYSTEM) |
| sh_css_sp_group.pipe[thread_id].input_system_mode |
| = (uint32_t)input_mode; |
| sh_css_sp_group.pipe[thread_id].port_id = port_id; |
| #endif |
| sh_css_sp_group.pipe[thread_id].dvs_frame_delay = (uint32_t)me->dvs_frame_delay; |
| |
| /* TODO: next indicates from which queues parameters need to be |
| sampled, needs checking/improvement */ |
| if (ia_css_pipeline_uses_params(me)) { |
| sh_css_sp_group.pipe[thread_id].pipe_config = |
| SH_CSS_PIPE_CONFIG_SAMPLE_PARAMS << thread_id; |
| } |
| |
| /* For continuous use-cases, SP copy is responsible for sampling the |
| * parameters */ |
| if (continuous) |
| sh_css_sp_group.pipe[thread_id].pipe_config = 0; |
| |
| sh_css_sp_group.pipe[thread_id].inout_port_config = me->inout_port_config; |
| |
| pipe = find_pipe_by_num(pipe_num); |
| assert(pipe != NULL); |
| if (pipe == NULL) { |
| return; |
| } |
| sh_css_sp_group.pipe[thread_id].scaler_pp_lut = sh_css_pipe_get_pp_gdc_lut(pipe); |
| |
| #if defined(SH_CSS_ENABLE_METADATA) |
| if (md_info != NULL && md_info->size > 0) { |
| sh_css_sp_group.pipe[thread_id].metadata.width = md_info->resolution.width; |
| sh_css_sp_group.pipe[thread_id].metadata.height = md_info->resolution.height; |
| sh_css_sp_group.pipe[thread_id].metadata.stride = md_info->stride; |
| sh_css_sp_group.pipe[thread_id].metadata.size = md_info->size; |
| ia_css_isys_convert_stream_format_to_mipi_format( |
| md_config->data_type, MIPI_PREDICTOR_NONE, |
| &sh_css_sp_group.pipe[thread_id].metadata.format); |
| } |
| #else |
| (void)md_config; |
| (void)md_info; |
| #endif |
| |
| #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS) |
| sh_css_sp_group.pipe[thread_id].output_frame_queue_id = (uint32_t)SH_CSS_INVALID_QUEUE_ID; |
| if (IA_CSS_PIPE_ID_COPY != pipe_id) { |
| ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, (enum sh_css_queue_id *)(&sh_css_sp_group.pipe[thread_id].output_frame_queue_id)); |
| } |
| #endif |
| |
| #ifdef ISP2401 |
| /* For the shading correction type 1 (the legacy shading table conversion in css is not used), |
| * the parameters are passed to the isp for the shading table centering. |
| */ |
| if (internal_frame_origin_bqs_on_sctbl != NULL && |
| params != NULL && params->shading_settings.enable_shading_table_conversion == 0) { |
| sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_x_bqs_on_sctbl |
| = (uint32_t)internal_frame_origin_bqs_on_sctbl->x; |
| sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_y_bqs_on_sctbl |
| = (uint32_t)internal_frame_origin_bqs_on_sctbl->y; |
| } else { |
| sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_x_bqs_on_sctbl = 0; |
| sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_y_bqs_on_sctbl = 0; |
| } |
| |
| #endif |
| IA_CSS_LOG("pipe_id %d port_config %08x", |
| pipe_id, sh_css_sp_group.pipe[thread_id].inout_port_config); |
| |
| for (stage = me->stages, num = 0; stage; stage = stage->next, num++) { |
| sh_css_sp_group.pipe[thread_id].num_stages++; |
| if (is_sp_stage(stage)) { |
| sp_init_sp_stage(stage, pipe_num, two_ppc, |
| copy_ovrd, if_config_index); |
| } else { |
| if ((stage->stage_num != 0) || SH_CSS_PIPE_PORT_CONFIG_IS_CONTINUOUS(me->inout_port_config)) |
| tmp_if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED; |
| else |
| tmp_if_config_index = if_config_index; |
| sp_init_stage(stage, pipe_num, |
| xnr, tmp_if_config_index, two_ppc); |
| } |
| |
| store_sp_stage_data(pipe_id, pipe_num, num); |
| } |
| sh_css_sp_group.pipe[thread_id].pipe_config |= (uint32_t) |
| (me->acquire_isp_each_stage << IA_CSS_ACQUIRE_ISP_POS); |
| store_sp_group_data(); |
| |
| } |
| |
| void |
| sh_css_sp_uninit_pipeline(unsigned int pipe_num) |
| { |
| unsigned int thread_id; |
| ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); |
| /*memset(&sh_css_sp_group.pipe[thread_id], 0, sizeof(struct sh_css_sp_pipeline));*/ |
| sh_css_sp_group.pipe[thread_id].num_stages = 0; |
| } |
| |
| bool sh_css_write_host2sp_command(enum host2sp_commands host2sp_command) |
| { |
| unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; |
| unsigned int offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_command) |
| / sizeof(int); |
| enum host2sp_commands last_cmd = host2sp_cmd_error; |
| (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */ |
| |
| /* Previous command must be handled by SP (by design) */ |
| last_cmd = load_sp_array_uint(host_sp_com, offset); |
| if (last_cmd != host2sp_cmd_ready) |
| IA_CSS_ERROR("last host command not handled by SP(%d)", last_cmd); |
| |
| store_sp_array_uint(host_sp_com, offset, host2sp_command); |
| |
| return (last_cmd == host2sp_cmd_ready); |
| } |
| |
| enum host2sp_commands |
| sh_css_read_host2sp_command(void) |
| { |
| unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; |
| unsigned int offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_command) |
| / sizeof(int); |
| (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */ |
| return (enum host2sp_commands)load_sp_array_uint(host_sp_com, offset); |
| } |
| |
| |
| /* |
| * Frame data is no longer part of the sp_stage structure but part of a |
| * seperate structure. The aim is to make the sp_data struct static |
| * (it defines a pipeline) and that the dynamic (per frame) data is stored |
| * separetly. |
| * |
| * This function must be called first every where were you start constructing |
| * a new pipeline by defining one or more stages with use of variable |
| * sh_css_sp_stage. Even the special cases like accelerator and copy_frame |
| * These have a pipeline of just 1 stage. |
| */ |
| void |
| sh_css_init_host2sp_frame_data(void) |
| { |
| /* Clean table */ |
| unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; |
| |
| (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */ |
| /* |
| * rvanimme: don't clean it to save static frame info line ref_in |
| * ref_out, and tnr_frames. Once this static data is in a |
| * seperate data struct, this may be enable (but still, there is |
| * no need for it) |
| */ |
| } |
| |
| |
| /** |
| * @brief Update the offline frame information in host_sp_communication. |
| * Refer to "sh_css_sp.h" for more details. |
| */ |
| void |
| sh_css_update_host2sp_offline_frame( |
| unsigned frame_num, |
| struct ia_css_frame *frame, |
| struct ia_css_metadata *metadata) |
| { |
| unsigned int HIVE_ADDR_host_sp_com; |
| unsigned int offset; |
| |
| (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */ |
| |
| assert(frame_num < NUM_CONTINUOUS_FRAMES); |
| |
| /* Write new frame data into SP DMEM */ |
| HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; |
| offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_offline_frames) |
| / sizeof(int); |
| offset += frame_num; |
| store_sp_array_uint(host_sp_com, offset, frame ? frame->data : 0); |
| |
| /* Write metadata buffer into SP DMEM */ |
| offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_offline_metadata) |
| / sizeof(int); |
| offset += frame_num; |
| store_sp_array_uint(host_sp_com, offset, metadata ? metadata->address : 0); |
| } |
| |
| #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401) |
| /** |
| * @brief Update the mipi frame information in host_sp_communication. |
| * Refer to "sh_css_sp.h" for more details. |
| */ |
| void |
| sh_css_update_host2sp_mipi_frame( |
| unsigned frame_num, |
| struct ia_css_frame *frame) |
| { |
| unsigned int HIVE_ADDR_host_sp_com; |
| unsigned int offset; |
| |
| (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */ |
| |
| /* MIPI buffers are dedicated to port, so now there are more of them. */ |
| assert(frame_num < (N_CSI_PORTS * NUM_MIPI_FRAMES_PER_STREAM)); |
| |
| /* Write new frame data into SP DMEM */ |
| HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; |
| offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_mipi_frames) |
| / sizeof(int); |
| offset += frame_num; |
| |
| store_sp_array_uint(host_sp_com, offset, |
| frame ? frame->data : 0); |
| } |
| |
| /** |
| * @brief Update the mipi metadata information in host_sp_communication. |
| * Refer to "sh_css_sp.h" for more details. |
| */ |
| void |
| sh_css_update_host2sp_mipi_metadata( |
| unsigned frame_num, |
| struct ia_css_metadata *metadata) |
| { |
| unsigned int HIVE_ADDR_host_sp_com; |
| unsigned int o; |
| |
| (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */ |
| |
| /* MIPI buffers are dedicated to port, so now there are more of them. */ |
| assert(frame_num < (N_CSI_PORTS * NUM_MIPI_FRAMES_PER_STREAM)); |
| |
| /* Write new frame data into SP DMEM */ |
| HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; |
| o = offsetof(struct host_sp_communication, host2sp_mipi_metadata) |
| / sizeof(int); |
| o += frame_num; |
| store_sp_array_uint(host_sp_com, o, |
| metadata ? metadata->address : 0); |
| } |
| |
| void |
| sh_css_update_host2sp_num_mipi_frames(unsigned num_frames) |
| { |
| unsigned int HIVE_ADDR_host_sp_com; |
| unsigned int offset; |
| |
| (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */ |
| |
| /* Write new frame data into SP DMEM */ |
| HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; |
| offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_num_mipi_frames) |
| / sizeof(int); |
| |
| store_sp_array_uint(host_sp_com, offset, num_frames); |
| } |
| #endif |
| |
| void |
| sh_css_update_host2sp_cont_num_raw_frames(unsigned num_frames, bool set_avail) |
| { |
| const struct ia_css_fw_info *fw; |
| unsigned int HIVE_ADDR_host_sp_com; |
| unsigned int extra_num_frames, avail_num_frames; |
| unsigned int offset, offset_extra; |
| |
| (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */ |
| |
| /* Write new frame data into SP DMEM */ |
| fw = &sh_css_sp_fw; |
| HIVE_ADDR_host_sp_com = fw->info.sp.host_sp_com; |
| if (set_avail) { |
| offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_cont_avail_num_raw_frames) |
| / sizeof(int); |
| avail_num_frames = load_sp_array_uint(host_sp_com, offset); |
| extra_num_frames = num_frames - avail_num_frames; |
| offset_extra = (unsigned int)offsetof(struct host_sp_communication, host2sp_cont_extra_num_raw_frames) |
| / sizeof(int); |
| store_sp_array_uint(host_sp_com, offset_extra, extra_num_frames); |
| } else |
| offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_cont_target_num_raw_frames) |
| / sizeof(int); |
| |
| store_sp_array_uint(host_sp_com, offset, num_frames); |
| } |
| |
| void |
| sh_css_event_init_irq_mask(void) |
| { |
| int i; |
| unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; |
| unsigned int offset; |
| struct sh_css_event_irq_mask event_irq_mask_init; |
| |
| event_irq_mask_init.or_mask = IA_CSS_EVENT_TYPE_ALL; |
| event_irq_mask_init.and_mask = IA_CSS_EVENT_TYPE_NONE; |
| (void)HIVE_ADDR_host_sp_com; /* Suppress warnings in CRUN */ |
| |
| assert(sizeof(event_irq_mask_init) % HRT_BUS_BYTES == 0); |
| for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { |
| offset = (unsigned int)offsetof(struct host_sp_communication, |
| host2sp_event_irq_mask[i]); |
| assert(offset % HRT_BUS_BYTES == 0); |
| sp_dmem_store(SP0_ID, |
| (unsigned int)sp_address_of(host_sp_com) + offset, |
| &event_irq_mask_init, sizeof(event_irq_mask_init)); |
| } |
| |
| } |
| |
| enum ia_css_err |
| ia_css_pipe_set_irq_mask(struct ia_css_pipe *pipe, |
| unsigned int or_mask, |
| unsigned int and_mask) |
| { |
| unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; |
| unsigned int offset; |
| struct sh_css_event_irq_mask event_irq_mask; |
| unsigned int pipe_num; |
| |
| assert(pipe != NULL); |
| |
| assert(IA_CSS_PIPE_ID_NUM == NR_OF_PIPELINES); |
| /* Linux kernel does not have UINT16_MAX |
| * Therefore decided to comment out these 2 asserts for Linux |
| * Alternatives that were not chosen: |
| * - add a conditional #define for UINT16_MAX |
| * - compare with (uint16_t)~0 or 0xffff |
| * - different assert for Linux and Windows |
| */ |
| #ifndef __KERNEL__ |
| assert(or_mask <= UINT16_MAX); |
| assert(and_mask <= UINT16_MAX); |
| #endif |
| |
| (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */ |
| |
| IA_CSS_LOG("or_mask=%x, and_mask=%x", or_mask, and_mask); |
| event_irq_mask.or_mask = (uint16_t)or_mask; |
| event_irq_mask.and_mask = (uint16_t)and_mask; |
| |
| pipe_num = ia_css_pipe_get_pipe_num(pipe); |
| if (pipe_num >= IA_CSS_PIPE_ID_NUM) |
| return IA_CSS_ERR_INTERNAL_ERROR; |
| offset = (unsigned int)offsetof(struct host_sp_communication, |
| host2sp_event_irq_mask[pipe_num]); |
| assert(offset % HRT_BUS_BYTES == 0); |
| sp_dmem_store(SP0_ID, |
| (unsigned int)sp_address_of(host_sp_com) + offset, |
| &event_irq_mask, sizeof(event_irq_mask)); |
| |
| return IA_CSS_SUCCESS; |
| } |
| |
| enum ia_css_err |
| ia_css_event_get_irq_mask(const struct ia_css_pipe *pipe, |
| unsigned int *or_mask, |
| unsigned int *and_mask) |
| { |
| unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; |
| unsigned int offset; |
| struct sh_css_event_irq_mask event_irq_mask; |
| unsigned int pipe_num; |
| |
| (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */ |
| |
| IA_CSS_ENTER_LEAVE(""); |
| |
| assert(pipe != NULL); |
| assert(IA_CSS_PIPE_ID_NUM == NR_OF_PIPELINES); |
| |
| pipe_num = ia_css_pipe_get_pipe_num(pipe); |
| if (pipe_num >= IA_CSS_PIPE_ID_NUM) |
| return IA_CSS_ERR_INTERNAL_ERROR; |
| offset = (unsigned int)offsetof(struct host_sp_communication, |
| host2sp_event_irq_mask[pipe_num]); |
| assert(offset % HRT_BUS_BYTES == 0); |
| sp_dmem_load(SP0_ID, |
| (unsigned int)sp_address_of(host_sp_com) + offset, |
| &event_irq_mask, sizeof(event_irq_mask)); |
| |
| if (or_mask) |
| *or_mask = event_irq_mask.or_mask; |
| |
| if (and_mask) |
| *and_mask = event_irq_mask.and_mask; |
| |
| return IA_CSS_SUCCESS; |
| } |
| |
| void |
| sh_css_sp_set_sp_running(bool flag) |
| { |
| sp_running = flag; |
| } |
| |
| bool |
| sh_css_sp_is_running(void) |
| { |
| return sp_running; |
| } |
| |
| void |
| sh_css_sp_start_isp(void) |
| { |
| const struct ia_css_fw_info *fw; |
| unsigned int HIVE_ADDR_sp_sw_state; |
| |
| fw = &sh_css_sp_fw; |
| HIVE_ADDR_sp_sw_state = fw->info.sp.sw_state; |
| |
| |
| if (sp_running) |
| return; |
| |
| (void)HIVE_ADDR_sp_sw_state; /* Suppres warnings in CRUN */ |
| |
| /* no longer here, sp started immediately */ |
| /*ia_css_debug_pipe_graph_dump_epilogue();*/ |
| |
| store_sp_group_data(); |
| store_sp_per_frame_data(fw); |
| |
| sp_dmem_store_uint32(SP0_ID, |
| (unsigned int)sp_address_of(sp_sw_state), |
| (uint32_t)(IA_CSS_SP_SW_TERMINATED)); |
| |
| |
| /* Note 1: The sp_start_isp function contains a wait till |
| * the input network is configured by the SP. |
| * Note 2: Not all SP binaries supports host2sp_commands. |
| * In case a binary does support it, the host2sp_command |
| * will have status cmd_ready after return of the function |
| * sh_css_hrt_sp_start_isp. There is no race-condition here |
| * because only after the process_frame command has been |
| * received, the SP starts configuring the input network. |
| */ |
| |
| /* we need to set sp_running before we call ia_css_mmu_invalidate_cache |
| * as ia_css_mmu_invalidate_cache checks on sp_running to |
| * avoid that it accesses dmem while the SP is not powered |
| */ |
| sp_running = true; |
| ia_css_mmu_invalidate_cache(); |
| /* Invalidate all MMU caches */ |
| mmu_invalidate_cache_all(); |
| |
| ia_css_spctrl_start(SP0_ID); |
| |
| } |
| |
| bool |
| ia_css_isp_has_started(void) |
| { |
| const struct ia_css_fw_info *fw = &sh_css_sp_fw; |
| unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started = fw->info.sp.isp_started; |
| (void)HIVE_ADDR_ia_css_ispctrl_sp_isp_started; /* Suppres warnings in CRUN */ |
| |
| return (bool)load_sp_uint(ia_css_ispctrl_sp_isp_started); |
| } |
| |
| |
| /** |
| * @brief Initialize the DMA software-mask in the debug mode. |
| * Refer to "sh_css_sp.h" for more details. |
| */ |
| bool |
| sh_css_sp_init_dma_sw_reg(int dma_id) |
| { |
| int i; |
| |
| /* enable all the DMA channels */ |
| for (i = 0; i < N_DMA_CHANNEL_ID; i++) { |
| /* enable the writing request */ |
| sh_css_sp_set_dma_sw_reg(dma_id, |
| i, |
| 0, |
| true); |
| /* enable the reading request */ |
| sh_css_sp_set_dma_sw_reg(dma_id, |
| i, |
| 1, |
| true); |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @brief Set the DMA software-mask in the debug mode. |
| * Refer to "sh_css_sp.h" for more details. |
| */ |
| bool |
| sh_css_sp_set_dma_sw_reg(int dma_id, |
| int channel_id, |
| int request_type, |
| bool enable) |
| { |
| uint32_t sw_reg; |
| uint32_t bit_val; |
| uint32_t bit_offset; |
| uint32_t bit_mask; |
| |
| (void)dma_id; |
| |
| assert(channel_id >= 0 && channel_id < N_DMA_CHANNEL_ID); |
| assert(request_type >= 0); |
| |
| /* get the software-mask */ |
| sw_reg = |
| sh_css_sp_group.debug.dma_sw_reg; |
| |
| /* get the offest of the target bit */ |
| bit_offset = (8 * request_type) + channel_id; |
| |
| /* clear the value of the target bit */ |
| bit_mask = ~(1 << bit_offset); |
| sw_reg &= bit_mask; |
| |
| /* set the value of the bit for the DMA channel */ |
| bit_val = enable ? 1 : 0; |
| bit_val <<= bit_offset; |
| sw_reg |= bit_val; |
| |
| /* update the software status of DMA channels */ |
| sh_css_sp_group.debug.dma_sw_reg = sw_reg; |
| |
| return true; |
| } |
| |
| void |
| sh_css_sp_reset_global_vars(void) |
| { |
| memset(&sh_css_sp_group, 0, sizeof(struct sh_css_sp_group)); |
| memset(&sh_css_sp_stage, 0, sizeof(struct sh_css_sp_stage)); |
| memset(&sh_css_isp_stage, 0, sizeof(struct sh_css_isp_stage)); |
| memset(&sh_css_sp_output, 0, sizeof(struct sh_css_sp_output)); |
| memset(&per_frame_data, 0, sizeof(struct sh_css_sp_per_frame_data)); |
| } |