diff --git a/drivers/cam_sensor_module/cam_tpg/cam_tpg_core.c b/drivers/cam_sensor_module/cam_tpg/cam_tpg_core.c index b23a688e3a..f8a8f45837 100644 --- a/drivers/cam_sensor_module/cam_tpg/cam_tpg_core.c +++ b/drivers/cam_sensor_module/cam_tpg/cam_tpg_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "cam_tpg_core.h" @@ -388,15 +389,31 @@ static int cam_tpg_validate_cmd_descriptor( break; } case TPG_CMD_TYPE_STREAM_CONFIG: { - if (cmd_header->size != sizeof(struct tpg_stream_config_t)) { + if (cmd_header->cmd_version == 3 && + cmd_header->size != sizeof(struct tpg_stream_config_v3_t)) { CAM_ERR(CAM_TPG, "Got invalid stream config command recv: %d exp: %d", - cmd_header->size, - sizeof(struct tpg_stream_config_t)); + cmd_header->size, + sizeof(struct tpg_stream_config_v3_t)); + + rc = -EINVAL; + goto end; + } else if (cmd_header->cmd_version == 2 && + cmd_header->size != sizeof(struct tpg_stream_config_t)) { + CAM_ERR(CAM_TPG, "Got invalid stream config cmd recv: %d exp: %d", + cmd_header->size, + sizeof(struct tpg_stream_config_t)); + + rc = -EINVAL; + goto end; + } else if (cmd_header->cmd_version == 1 && + cmd_header->size != sizeof(struct tpg_old_stream_config_t)) { + CAM_ERR(CAM_TPG, "Got invalid stream config cmd recv: %d exp: %d", + cmd_header->size, + sizeof(struct tpg_old_stream_config_t)); rc = -EINVAL; goto end; } - CAM_INFO(CAM_TPG, "Got stream config cmd"); *cmd_type = TPG_CMD_TYPE_STREAM_CONFIG; break; } @@ -437,6 +454,7 @@ static int cam_tpg_cmd_buf_parse( for (i = 0; i < packet->num_cmd_buf; i++) { uint32_t cmd_type = TPG_CMD_TYPE_INVALID; uintptr_t cmd_addr; + struct tpg_command_header_t *cmd_header = NULL; cmd_desc = (struct cam_cmd_buf_desc *) ((uint32_t *)&packet->payload + @@ -448,14 +466,24 @@ static int cam_tpg_cmd_buf_parse( if (rc < 0) goto end; + cmd_header = (struct tpg_command_header_t *)cmd_addr; + switch (cmd_type) { case TPG_CMD_TYPE_GLOBAL_CONFIG: rc = tpg_hw_copy_global_config(&tpg_dev->tpg_hw, (struct tpg_global_config_t *)cmd_addr); break; case TPG_CMD_TYPE_STREAM_CONFIG: { - rc = tpg_hw_add_stream(&tpg_dev->tpg_hw, - (struct tpg_stream_config_t *)cmd_addr); + if (cmd_header->cmd_version == 3) { + rc = tpg_hw_add_stream_v3(&tpg_dev->tpg_hw, + (struct tpg_stream_config_v3_t *)cmd_addr); + CAM_DBG(CAM_TPG, "Stream config v3"); + } else if (cmd_header->cmd_version == 1 || + cmd_header->cmd_version == 2) { + rc = tpg_hw_add_stream(&tpg_dev->tpg_hw, + (struct tpg_stream_config_t *)cmd_addr); + CAM_DBG(CAM_TPG, "Stream config"); + } break; } case TPG_CMD_TYPE_ILLUMINATION_CONFIG: diff --git a/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.c b/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.c index 267d69e8d0..e3f2ff0f1e 100644 --- a/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.c +++ b/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.c @@ -228,6 +228,75 @@ int dump_stream_configs(int hw_idx, return 0; } +int dump_stream_configs_v3(int hw_idx, + int stream_idx, + struct tpg_stream_config_v3_t *stream) +{ +#ifdef __TPG_DEBUG_DUMP__ + CAM_DBG(CAM_TPG, "TPG[%d][%d] pattern_type : %s", + hw_idx, + stream_idx, + tpg_pattern_type_strings[stream->pattern_type]); + CAM_DBG(CAM_TPG, "TPG[%d][%d] cb_mode : %s", + hw_idx, + stream_idx, + tpg_color_bar_mode_strings[stream->cb_mode]); + CAM_DBG(CAM_TPG, "TPG[%d][%d] frame_count : %d", + hw_idx, + stream_idx, + stream->frame_count); + CAM_DBG(CAM_TPG, "TPG[%d][%d] stream_type : %s", + hw_idx, + stream_idx, + tpg_stream_type_strings[stream->stream_type]); + CAM_DBG(CAM_TPG, "TPG[%d][%d] left : %d", + hw_idx, + stream_idx, + stream->stream_dimension.left); + CAM_DBG(CAM_TPG, "TPG[%d][%d] top : %d", + hw_idx, + stream_idx, + stream->stream_dimension.top); + CAM_DBG(CAM_TPG, "TPG[%d][%d] width : %d", + hw_idx, + stream_idx, + stream->stream_dimension.width); + CAM_DBG(CAM_TPG, "TPG[%d][%d] height : %d", + hw_idx, + stream_idx, + stream->stream_dimension.height); + CAM_DBG(CAM_TPG, "TPG[%d][%d] pixel_depth : %d", + hw_idx, + stream_idx, + stream->pixel_depth); + CAM_DBG(CAM_TPG, "TPG[%d][%d] cfa_arrangement : %d", + hw_idx, + stream_idx, + stream->cfa_arrangement); + CAM_DBG(CAM_TPG, "TPG[%d][%d] output_format : %s", + hw_idx, + stream_idx, + tpg_image_format_type_strings[stream->output_format]); + CAM_DBG(CAM_TPG, "TPG[%d][%d] vc : 0x%x", + hw_idx, + stream_idx, + stream->vc); + CAM_DBG(CAM_TPG, "TPG[%d][%d] dt : 0x%x", + hw_idx, + stream_idx, + stream->dt); + CAM_DBG(CAM_TPG, "TPG[%d][%d] hbi : %d", + hw_idx, + stream_idx, + stream->hbi); + CAM_DBG(CAM_TPG, "TPG[%d][%d] vbi : %d", + hw_idx, + stream_idx, + stream->vbi); +#endif + return 0; +} + static int tpg_hw_soc_disable(struct tpg_hw *hw) { @@ -239,13 +308,15 @@ static int tpg_hw_soc_disable(struct tpg_hw *hw) } rc = cam_soc_util_disable_platform_resource(hw->soc_info, true, false); - if (rc) + if (rc) { CAM_ERR(CAM_TPG, "TPG[%d] Disable platform failed %d", - hw->hw_idx, rc); - + hw->hw_idx, rc); + return rc; + } if ((rc = cam_cpas_stop(hw->cpas_handle))) { CAM_ERR(CAM_TPG, "TPG[%d] CPAS stop failed", - hw->hw_idx); + hw->hw_idx); + return rc; } else { hw->state = TPG_HW_STATE_HW_DISABLED; } @@ -280,7 +351,7 @@ static int tpg_hw_soc_enable( rc = cam_cpas_start(hw->cpas_handle, &ahb_vote, &axi_vote); if (rc) { CAM_ERR(CAM_TPG, "TPG[%d] CPAS start failed", - hw->hw_idx); + hw->hw_idx); rc = -EFAULT; goto end; } @@ -289,7 +360,7 @@ static int tpg_hw_soc_enable( clk_level, false); if (rc) { CAM_ERR(CAM_TPG, "TPG[%d] enable platform failed", - hw->hw_idx); + hw->hw_idx); goto stop_cpas; } hw->state = TPG_HW_STATE_HW_ENABLED; @@ -354,12 +425,67 @@ static int tpg_hw_start_default_new(struct tpg_hw *hw) return 0; } +static int tpg_hw_start_default_new_v3(struct tpg_hw *hw) +{ + int i = 0; + uint32_t stream_idx = 0; + int num_vcs = 0; + struct global_config_args globalargs = {0}; + + if (!hw || !hw->hw_info || + !hw->hw_info->ops || !hw->hw_info->ops->process_cmd) { + CAM_ERR(CAM_TPG, "Invalid argument"); + return -EINVAL; + } + + dump_global_configs(hw->hw_idx, &hw->global_config); + for (i = 0; i < hw->hw_info->max_vc_channels; i++) { + int dt_slot = 0; + struct vc_config_args_v3 vc_config = {0}; + struct list_head *pos = NULL, *pos_next = NULL; + struct tpg_hw_stream_v3 *entry = NULL, *vc_stream_entry = NULL; + + if (hw->vc_slots[i].vc == -1) + break; + num_vcs++; + vc_config.vc_slot = i; + vc_config.num_dts = hw->vc_slots[i].stream_count; + vc_stream_entry = list_first_entry(&hw->vc_slots[i].head, + struct tpg_hw_stream_v3, list); + vc_config.stream = &vc_stream_entry->stream; + hw->hw_info->ops->process_cmd(hw, + TPG_CONFIG_VC, &vc_config); + + list_for_each_safe(pos, pos_next, &hw->vc_slots[i].head) { + struct dt_config_args_v3 dt_config = {0}; + + entry = list_entry(pos, struct tpg_hw_stream_v3, list); + dump_stream_configs_v3(hw->hw_idx, + stream_idx++, + &entry->stream); + dt_config.vc_slot = i; + dt_config.dt_slot = dt_slot++; + dt_config.stream = &entry->stream; + hw->hw_info->ops->process_cmd(hw, TPG_CONFIG_DT, &dt_config); + } + } + + globalargs.num_vcs = num_vcs; + globalargs.globalconfig = &hw->global_config; + hw->hw_info->ops->process_cmd(hw, + TPG_CONFIG_CTRL, &globalargs); + + return 0; +} + + int tpg_hw_dump_status(struct tpg_hw *hw) { if (!hw || !hw->hw_info || !hw->hw_info->ops) return -EINVAL; switch (hw->hw_info->version) { case TPG_HW_VERSION_1_3: + case TPG_HW_VERSION_1_3_1: if (hw->hw_info->ops->dump_status) hw->hw_info->ops->dump_status(hw, NULL); break; @@ -385,14 +511,18 @@ int tpg_hw_start(struct tpg_hw *hw) break; case TPG_HW_VERSION_1_2: case TPG_HW_VERSION_1_3: + case TPG_HW_VERSION_1_3_1: if (hw->hw_info->ops->start) hw->hw_info->ops->start(hw, NULL); - tpg_hw_start_default_new(hw); + if (hw->stream_version == 1) + tpg_hw_start_default_new(hw); + else if (hw->stream_version == 3) + tpg_hw_start_default_new_v3(hw); cam_tpg_mem_dmp(hw->soc_info); break; default: CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version", - hw->hw_idx); + hw->hw_idx); rc = -EINVAL; break; } @@ -412,13 +542,25 @@ int tpg_hw_stop(struct tpg_hw *hw) case TPG_HW_VERSION_1_1: case TPG_HW_VERSION_1_2: case TPG_HW_VERSION_1_3: - if (hw->hw_info->ops->stop) + case TPG_HW_VERSION_1_3_1: + if (hw->hw_info->ops->stop) { rc = hw->hw_info->ops->stop(hw, NULL); + if (rc) { + CAM_ERR(CAM_TPG, "TPG[%d] hw stop failed %d", + hw->hw_idx, rc); + return rc; + } + } rc = tpg_hw_soc_disable(hw); + if (rc) { + CAM_ERR(CAM_TPG, "TPG[%d] hw soc disable failed %d", + hw->hw_idx, rc); + return rc; + } break; default: CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version", - hw->hw_idx); + hw->hw_idx); rc = -EINVAL; break; } @@ -441,11 +583,12 @@ int tpg_hw_acquire(struct tpg_hw *hw, case TPG_HW_VERSION_1_1: case TPG_HW_VERSION_1_2: case TPG_HW_VERSION_1_3: + case TPG_HW_VERSION_1_3_1: // Start Cpas and enable required clocks break; default: CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version", - hw->hw_idx); + hw->hw_idx); rc = -EINVAL; break; } @@ -465,10 +608,11 @@ int tpg_hw_release(struct tpg_hw *hw) case TPG_HW_VERSION_1_1: case TPG_HW_VERSION_1_2: case TPG_HW_VERSION_1_3: + case TPG_HW_VERSION_1_3_1: break; default: CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version", - hw->hw_idx); + hw->hw_idx); rc = -EINVAL; break; } @@ -526,14 +670,26 @@ static int tpg_hw_configure_init_settings( case TPG_HW_VERSION_1_1: case TPG_HW_VERSION_1_2: case TPG_HW_VERSION_1_3: + case TPG_HW_VERSION_1_3_1: clk_level = get_tpg_clk_level(hw); rc = tpg_hw_soc_enable(hw, clk_level); - if (hw->hw_info->ops->init) + if (rc) { + CAM_ERR(CAM_TPG, "TPG[%d] hw soc enable failed %d", + hw->hw_idx, rc); + return rc; + } + if (hw->hw_info->ops->init) { rc = hw->hw_info->ops->init(hw, settings); + if (rc) { + CAM_ERR(CAM_TPG, "TPG[%d] hw soc enable failed %d", + hw->hw_idx, rc); + return rc; + } + } break; default: CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version", - hw->hw_idx); + hw->hw_idx); rc = -EINVAL; break; } @@ -541,6 +697,47 @@ static int tpg_hw_configure_init_settings( return rc; } +static int tpg_hw_configure_init_settings_v3( + struct tpg_hw *hw, + struct tpg_hw_initsettings_v3 *settings) +{ + int rc = 0; + + if (!hw || !hw->hw_info || !hw->hw_info->ops) + return -EINVAL; + mutex_lock(&hw->mutex); + switch (hw->hw_info->version) { + case TPG_HW_VERSION_1_0: + case TPG_HW_VERSION_1_1: + case TPG_HW_VERSION_1_2: + case TPG_HW_VERSION_1_3: + case TPG_HW_VERSION_1_3_1: + rc = tpg_hw_soc_enable(hw, CAM_SVS_VOTE); + if (rc) { + CAM_ERR(CAM_TPG, "TPG[%d] hw soc enable failed %d", + hw->hw_idx, rc); + return rc; + } + if (hw->hw_info->ops->init) { + rc = hw->hw_info->ops->init(hw, settings); + if (rc) { + CAM_ERR(CAM_TPG, "TPG[%d] hw soc enable failed %d", + hw->hw_idx, rc); + return rc; + } + } + break; + default: + CAM_ERR(CAM_TPG, "TPG[%d] Unsupported HW Version", + hw->hw_idx); + rc = -EINVAL; + break; + } + mutex_unlock(&hw->mutex); + return rc; +} + + int tpg_hw_config( struct tpg_hw *hw, enum tpg_hw_cmd_t config_cmd, @@ -553,12 +750,17 @@ int tpg_hw_config( switch (config_cmd) { case TPG_HW_CMD_INIT_CONFIG: //validate_stream_list(hw); - tpg_hw_configure_init_settings(hw, - (struct tpg_hw_initsettings *)config_args); + if (hw->stream_version == 1) { + tpg_hw_configure_init_settings(hw, + (struct tpg_hw_initsettings *)config_args); + } else if (hw->stream_version == 3) { + tpg_hw_configure_init_settings_v3(hw, + (struct tpg_hw_initsettings_v3 *)config_args); + } break; default: CAM_ERR(CAM_TPG, "TPG[%d] Unsupported hw config command", - hw->hw_idx); + hw->hw_idx); rc = -EINVAL; break; } @@ -569,6 +771,7 @@ int tpg_hw_free_streams(struct tpg_hw *hw) { struct list_head *pos = NULL, *pos_next = NULL; struct tpg_hw_stream *entry; + struct tpg_hw_stream_v3 *entry_v3; int i = 0; if (!hw) @@ -583,10 +786,19 @@ int tpg_hw_free_streams(struct tpg_hw *hw) hw->vc_slots[i].slot_id = i; hw->vc_slots[i].vc = -1; hw->vc_slots[i].stream_count = 0; - list_for_each_safe(pos, pos_next, &hw->vc_slots[i].head) { - entry = list_entry(pos, struct tpg_hw_stream, list); - list_del(pos); - kfree(entry); + + if (hw->stream_version == 1) { + list_for_each_safe(pos, pos_next, &hw->vc_slots[i].head) { + entry = list_entry(pos, struct tpg_hw_stream, list); + list_del(pos); + kfree(entry); + } + } else if (hw->stream_version == 3) { + list_for_each_safe(pos, pos_next, &hw->vc_slots[i].head) { + entry_v3 = list_entry(pos, struct tpg_hw_stream_v3, list); + list_del(pos); + kfree(entry_v3); + } } INIT_LIST_HEAD(&(hw->vc_slots[i].head)); } @@ -671,6 +883,65 @@ static int assign_vc_slot( return rc; } +static int assign_vc_slot_v3( + struct tpg_hw *hw, + int vc, + struct tpg_hw_stream_v3 *stream + ) +{ + int rc = -EINVAL, i = 0, slot_matched = 0; + + if (!hw || !stream) + return -EINVAL; + + for (i = 0; i < hw->hw_info->max_vc_channels; i++) { + /* Found a matching slot */ + if (hw->vc_slots[i].vc == vc) { + slot_matched = 1; + if (hw->vc_slots[i].stream_count + < hw->hw_info->max_dt_channels_per_vc) { + list_add_tail(&stream->list, &hw->vc_slots[i].head); + hw->vc_slots[i].stream_count++; + hw->vc_slots[i].vc = vc; + rc = 0; + CAM_DBG(CAM_TPG, "vc[%d]dt[%d]=>slot[%d]", + vc, + stream->stream.dt, + i); + } else { + + /** + * already slot was assigned for this vc + * however this slot have been filled with + * full streams + */ + rc = -EINVAL; + CAM_ERR(CAM_TPG, "vc[%d]dt[%d]=>slot[%d] is overlfown", + vc, stream->stream.dt, i); + } + break; + } + + /** + * none of the above slots matched, and now found an empty slot + * so assigning stream to that slot + */ + if (hw->vc_slots[i].vc == -1) { + list_add_tail(&stream->list, &hw->vc_slots[i].head); + hw->vc_slots[i].stream_count++; + hw->vc_slots[i].vc = vc; + hw->vc_count++; + rc = 0; + CAM_DBG(CAM_TPG, "vc[%d]dt[%d]=>slot[%d]", vc, stream->stream.dt, i); + break; + } + } + if ((slot_matched == 0) && (rc != 0)) + CAM_ERR(CAM_TPG, "No slot matched"); + + return rc; +} + int tpg_hw_reset(struct tpg_hw *hw) { int rc = 0; @@ -686,13 +957,15 @@ int tpg_hw_reset(struct tpg_hw *hw) mutex_lock(&hw->mutex); if (hw->state != TPG_HW_STATE_HW_DISABLED) { rc = cam_soc_util_disable_platform_resource(hw->soc_info, true, false); - if (rc) + if (rc) { CAM_ERR(CAM_TPG, "TPG[%d] Disable platform failed %d", hw->hw_idx, rc); - + return rc; + } rc = cam_cpas_stop(hw->cpas_handle); - if (rc) + if (rc) { CAM_ERR(CAM_TPG, "TPG[%d] CPAS stop failed", hw->hw_idx); - + return rc; + } hw->state = TPG_HW_STATE_HW_DISABLED; } mutex_unlock(&hw->mutex); @@ -711,11 +984,12 @@ int tpg_hw_add_stream( return -EINVAL; } + hw->stream_version = 1; mutex_lock(&hw->mutex); stream = kzalloc(sizeof(struct tpg_hw_stream), GFP_KERNEL); if (!stream) { CAM_ERR(CAM_TPG, "TPG[%d] stream allocation failed", - hw->hw_idx); + hw->hw_idx); mutex_unlock(&hw->mutex); return -ENOMEM; } @@ -727,3 +1001,33 @@ int tpg_hw_add_stream( mutex_unlock(&hw->mutex); return rc; } +int tpg_hw_add_stream_v3( + struct tpg_hw *hw, + struct tpg_stream_config_v3_t *cmd) +{ + int rc = 0; + struct tpg_hw_stream_v3 *stream = NULL; + + if (!hw || !cmd) { + CAM_ERR(CAM_TPG, "Invalid params"); + return -EINVAL; + } + + hw->stream_version = 3; + mutex_lock(&hw->mutex); + stream = kzalloc(sizeof(struct tpg_hw_stream_v3), GFP_KERNEL); + if (!stream) { + CAM_ERR(CAM_TPG, "TPG[%d] stream allocation failed", + hw->hw_idx); + mutex_unlock(&hw->mutex); + return -ENOMEM; + } + memcpy(&stream->stream, + cmd, + sizeof(struct tpg_stream_config_v3_t)); + + rc = assign_vc_slot_v3(hw, stream->stream.vc, stream); + mutex_unlock(&hw->mutex); + return rc; +} + diff --git a/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.h b/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.h index 0c0897c887..328a85aafc 100644 --- a/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.h +++ b/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.h @@ -12,10 +12,11 @@ #include "cam_soc_util.h" #include #include -#define TPG_HW_VERSION_1_0 0x10000000 -#define TPG_HW_VERSION_1_1 0x10000001 -#define TPG_HW_VERSION_1_2 0x10000002 -#define TPG_HW_VERSION_1_3 0x10000003 +#define TPG_HW_VERSION_1_0 0x10000000 +#define TPG_HW_VERSION_1_1 0x10000001 +#define TPG_HW_VERSION_1_2 0x10000002 +#define TPG_HW_VERSION_1_3 0x10000003 +#define TPG_HW_VERSION_1_3_1 0x10000004 struct tpg_hw; @@ -109,20 +110,34 @@ struct tpg_hw_stream { struct list_head list; }; +/** + * tpg_hw_stream_v3 : tpg hw stream version 2 + * + * @stream : tpg stream version 2 + * @list : entry to tpg stream list + */ +struct tpg_hw_stream_v3 { + struct tpg_stream_config_v3_t stream; + struct list_head list; +}; + + /** * tpg_hw : tpg hw * - * @hw_idx : hw id - * @state : tpg hw state - * @cpas_handle : handle to cpas - * @hw_info : tp hw info - * @soc_info : soc info - * @mutex : lock - * @stream_list : list of tpg stream - * @global_config : global configuration + * @hw_idx : hw id + * @stream_version : stream version + * @state : tpg hw state + * @cpas_handle : handle to cpas + * @hw_info : tp hw info + * @soc_info : soc info + * @mutex : lock + * @stream_list : list of tpg stream + * @global_config : global configuration */ struct tpg_hw { uint32_t hw_idx; + uint32_t stream_version; uint32_t state; uint32_t cpas_handle; uint32_t vc_count; @@ -189,6 +204,33 @@ struct dt_config_args { struct tpg_stream_config_t *stream; }; +/** + * @vc_config_args_v3 : arguments for vc config process cmd version 2 + * + * @vc_slot : slot to configure this vc + * @num_dts : number of dts in this vc + * @stream : output stream version 2 + */ +struct vc_config_args_v3 { + uint32_t vc_slot; + uint32_t num_dts; + struct tpg_stream_config_v3_t *stream; +}; + +/** + * dt_config_args_v3 : arguments for dt config process cmd version 2 + * + * @vc_slot : vc slot to configure this dt + * @dt_slot : dt slot to configure this dt + * @stream : stream packet to configure for this dt version 2 + */ +struct dt_config_args_v3 { + uint32_t vc_slot; + uint32_t dt_slot; + struct tpg_stream_config_v3_t *stream; +}; + + /** * global_config_args : tpg global config args * @@ -213,6 +255,20 @@ struct tpg_hw_initsettings { uint32_t num_streams; }; +/** + * tpg_hw_initsettings_v3 : initial configurations version 2 + * + * @global_config : global configuration + * @streamconfigs : array of stream configurations version 2 + * @num_streams : number of streams in strea config array + */ +struct tpg_hw_initsettings_v3 { + struct tpg_global_config_t globalconfig; + struct tpg_stream_config_v3_t *streamconfigs; + uint32_t num_streams; +}; + + /** * @brief dump the tpg memory info * @@ -243,6 +299,18 @@ int dump_global_configs(int idx, struct tpg_global_config_t *global); */ int dump_stream_configs(int hw_idx, int stream_idx, struct tpg_stream_config_t *stream); +/** + * @brief : dump stream config command version 2 + * + * @param hw_idx: hw index + * @param stream_idx: stream index + * @param stream: stream config command version 2 + * + * @return : 0 on success + */ +int dump_stream_configs_v3(int hw_idx, int stream_idx, struct tpg_stream_config_v3_t *stream); + + /** * @brief : dump any hw status registers * @@ -327,6 +395,17 @@ int tpg_hw_reset(struct tpg_hw *hw); */ int tpg_hw_add_stream(struct tpg_hw *hw, struct tpg_stream_config_t *cmd); +/** + * @brief : tp hw add stream version 2 + * + * @param hw: tpg hw instance + * @param cmd: tpg hw command version 2 + * + * @return : 0 on success + */ +int tpg_hw_add_stream_v3(struct tpg_hw *hw, struct tpg_stream_config_v3_t *cmd); + + /** * @brief : copy global config command * diff --git a/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3.c b/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3.c index f52ba5c20f..22370217f1 100644 --- a/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3.c +++ b/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3.c @@ -15,10 +15,19 @@ enum tpg_hw_v_1_3_encode_fomat_t { }; -#define FRAME_INTERLEAVE 0x0 -#define LINE_INTERLEAVE 0x1 -#define SHDR_INTERLEAVE 0x2 -#define SPARSE_PD_INTERLEAVE 0x3 +#define FRAME_INTERLEAVE 0x0 +#define LINE_INTERLEAVE 0x1 +#define SHDR_INTERLEAVE 0x2 +#define SPARSE_PD_INTERLEAVE 0x3 +#define CFA_PATTERN_ROW_WIDTH 8 +#define CFA_PATTERN_BITS_PER_INDEX 2 +#define Invalid 0x0 +#define Red 0x0 +#define Green 0x1 +#define Blue 0x2 +#define IR 0x3 +#define Mono 0x3 + static int get_tpg_vc_dt_pattern_id( enum tpg_interleaving_format_t vc_dt_pattern) { @@ -82,7 +91,6 @@ static int configure_global_configs( (1 << tpg_reg->tpg_en_shift_val); cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_ctrl); CAM_DBG(CAM_TPG, "tpg[%d] tpg_ctrl=0x%x", hw->hw_idx, val); - return 0; } @@ -129,6 +137,149 @@ static int get_tpg_payload_mode(enum tpg_pattern_t pattern) return COLOR_BARS; } +static int get_pixel_coordinate( + int cfa_pattern_start_index, + int cfa_pattern_end_index, + uint32_t *val, + struct tpg_stream_config_v3_t *configs) +{ + uint32_t shift = 0; + int idx = 0; + int i = 0; + int j = 0; + *val = 0; + for (i = cfa_pattern_start_index; i < cfa_pattern_end_index; i++) { + for (j = 0; j < configs->cfa_info.pattern_width; j++) { + shift = ((i * CFA_PATTERN_ROW_WIDTH) + j) * + CFA_PATTERN_BITS_PER_INDEX; + idx = i * configs->cfa_info.pattern_height + j; + *val |= (configs->cfa_info.pixel_coordinate[idx].pixel_type) << shift; + } + } + return 0; +} + +static int configure_xcfa_array_v3( + struct tpg_hw *hw, + struct tpg_stream_config_v3_t *configs) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_tpg_ver_1_3_reg_offset *tpg_reg = NULL; + uint32_t val = 0; + + if (!hw || !hw->hw_info || !hw->hw_info->hw_data) { + CAM_ERR(CAM_TPG, "invalid params"); + return -EINVAL; + } + tpg_reg = hw->hw_info->hw_data; + + soc_info = hw->soc_info; + + switch (configs->xcfa_type) { + case XCFA_TYPE_RGBIR: + get_pixel_coordinate(0, 2, &val, configs); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color0); + get_pixel_coordinate(2, configs->cfa_info.pattern_height, &val, configs); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color1); + break; + case XCFA_TYPE_QUADCFA: + get_pixel_coordinate(0, 2, &val, configs); + CAM_DBG(CAM_TPG, "val = 0x%x", val); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color0); + get_pixel_coordinate(2, configs->cfa_info.pattern_height, &val, configs); + CAM_DBG(CAM_TPG, "val = 0x%x", val); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color1); + break; + case XCFA_TYPE_THREEXTHREECFA: + get_pixel_coordinate(0, 2, &val, configs); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color0); + get_pixel_coordinate(2, 4, &val, configs); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color1); + get_pixel_coordinate(4, configs->cfa_info.pattern_height, &val, configs); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color2); + break; + case XCFA_TYPE_FOURXFOURCFA: + get_pixel_coordinate(0, 2, &val, configs); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color0); + get_pixel_coordinate(2, 4, &val, configs); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color1); + get_pixel_coordinate(4, 6, &val, configs); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color2); + get_pixel_coordinate(6, configs->cfa_info.pattern_height, &val, configs); + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_color_bar_cfa_color3); + break; + default: + break; + } + return 0; +} + +static int configure_dt_v3( + struct tpg_hw *hw, + uint32_t vc_slot, + uint32_t dt_slot, + struct tpg_stream_config_v3_t *stream) +{ + uint32_t val; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_tpg_ver_1_3_reg_offset *tpg_reg = NULL; + + if (!hw || !hw->hw_info || !hw->hw_info->hw_data) { + CAM_ERR(CAM_TPG, "invalid params"); + return -EINVAL; + } + + tpg_reg = hw->hw_info->hw_data; + + soc_info = hw->soc_info; + + CAM_DBG(CAM_TPG, "TPG[%d] slot(%d,%d) <= dt:%d", + hw->hw_idx, + vc_slot, + dt_slot, + stream->dt); + + val = (((stream->stream_dimension.width & 0xFFFF) << 16) | + (stream->stream_dimension.height & 0xFFFF)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_vc0_dt_0_cfg_0 + + (0x60 * vc_slot) + (dt_slot * 0x0c)); + CAM_DBG(CAM_TPG, "TPG[%d] vc%d_dt%d_cfg_0=0x%x", + hw->hw_idx, + vc_slot, dt_slot, val); + + cam_io_w_mb(stream->dt, + soc_info->reg_map[0].mem_base + + tpg_reg->tpg_vc0_dt_0_cfg_1 + + (0x60 * vc_slot) + (dt_slot * 0x0c)); + CAM_DBG(CAM_TPG, "TPG[%d] vc%d_dt%d_cfg_1=0x%x", + hw->hw_idx, + vc_slot, dt_slot, stream->dt); + + val = ((get_tpg_encode_format(stream->pixel_depth) & 0xF) << + tpg_reg->tpg_dt_encode_format_shift) | + get_tpg_payload_mode(stream->pattern_type); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_vc0_dt_0_cfg_2 + + (0x60 * vc_slot) + (dt_slot * 0x0c)); + CAM_DBG(CAM_TPG, "TPG[%d] vc%d_dt%d_cfg_2=0x%x", + hw->hw_idx, + vc_slot, dt_slot, val); + + return 0; +} + static int configure_dt( struct tpg_hw *hw, uint32_t vc_slot, @@ -184,6 +335,100 @@ static int configure_dt( return 0; } + + +#define VC1_GAIN 0x100 + +static int configure_vc_v3( + struct tpg_hw *hw, + uint32_t vc_slot, + int num_dts, + struct tpg_stream_config_v3_t *stream) +{ + uint32_t val = 0; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_tpg_ver_1_3_reg_offset *tpg_reg = NULL; + + if (!hw || !hw->hw_info || !hw->hw_info->hw_data) { + CAM_ERR(CAM_TPG, "invalid params"); + return -EINVAL; + } + tpg_reg = hw->hw_info->hw_data; + + soc_info = hw->soc_info; + /* Use CFA pattern here */ + if (stream->output_format == TPG_IMAGE_FORMAT_QCFA) + val |= (1 << tpg_reg->tpg_color_bar_qcfa_en_shift); + + if (stream->cb_mode == TPG_COLOR_BAR_MODE_SPLIT) + val |= (1 << tpg_reg->tpg_split_en_shift); + + if (stream->cfa_info_exist != 0) { + val |= ((stream->cfa_info.pattern_height - 1) << tpg_reg->tpg_size_y_shift); + val |= ((stream->cfa_info.pattern_width - 1) << tpg_reg->tpg_size_x_shift); + val |= (1 << tpg_reg->tpg_xcfa_en_shift); + configure_xcfa_array_v3(hw, stream); + } + + CAM_DBG(CAM_TPG, "TPG[%d] period: %d", hw->hw_idx, stream->rotate_period); + val |= ((stream->rotate_period & 0x3F) << + tpg_reg->tpg_color_bar_qcfa_rotate_period_shift); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_vc0_color_bar_cfg + (0x60 * vc_slot)); + CAM_DBG(CAM_TPG, "TPG[%d] vc%d_color_bar_cfg=0x%x", + hw->hw_idx, + vc_slot, val); + + val = stream->hbi; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_vc0_hbi_cfg + (0x60 * vc_slot)); + CAM_DBG(CAM_TPG, "TPG[%d] vc%d_hbi_cfg=0x%x", + hw->hw_idx, + vc_slot, val); + + val = stream->vbi; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_vc0_vbi_cfg + (0x60 * vc_slot)); + CAM_DBG(CAM_TPG, "TPG[%d] vc%d_vbi_cgf=0x%x", + hw->hw_idx, + vc_slot, val); + + cam_io_w_mb(0x12345678, + soc_info->reg_map[0].mem_base + + tpg_reg->tpg_vc0_lfsr_seed + (0x60 * vc_slot)); + + val = ((0 << tpg_reg->tpg_num_frames_shift_val) | + ((num_dts-1) << tpg_reg->tpg_num_dts_shift_val) | + stream->vc); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_vc0_cfg0 + (0x60 * vc_slot)); + CAM_DBG(CAM_TPG, "TPG[%d] vc%d_cfg0=0x%x", + hw->hw_idx, + vc_slot, val); + if (hw->hw_info->shdr_overlap == 1) { + cam_io_w_mb(hw->hw_info->shdr_overlap << tpg_reg->tpg_overlap_shdr_en_shift, + soc_info->reg_map[0].mem_base + tpg_reg->tpg_ctrl); + } + if (hw->hw_info->shdr_offset_num_batch >= 0 && vc_slot > 0) { + val = (VC1_GAIN << tpg_reg->tpg_gain_shift); + val |= (hw->hw_info->shdr_offset_num_batch << + tpg_reg->tpg_shdr_offset_num_batch_shift); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_vc1_gain_cfg + (0x60 * (vc_slot-1))); + val = ((stream->shdr_line_offset0 * vc_slot) + << tpg_reg->tpg_shdr_line_offset0_shift); + val |= ((stream->shdr_line_offset1 * vc_slot) + << tpg_reg->tpg_shdr_line_offset1_shift); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + tpg_reg->tpg_vc1_shdr_cfg + (0x60 * (vc_slot-1))); + CAM_DBG(CAM_TPG, "TPG[%d] vc%d_cfg0=0x%x shdr", + hw->hw_idx, + vc_slot, val); + } + + return 0; +} + #define RGGB_IR_0 0x00770091 #define RGGB_IR_1 0x00770019 #define RGGB_2x2 0x05055A5A @@ -258,7 +503,7 @@ static int configure_vc( CAM_ERR(CAM_TPG, "invalid params"); return -EINVAL; } - tpg_reg = hw->hw_info->hw_data; + tpg_reg = hw->hw_info->hw_data; soc_info = hw->soc_info; /* Use CFA pattern here */ @@ -309,7 +554,7 @@ static int configure_vc( tpg_reg->tpg_vc0_lfsr_seed + (0x60 * vc_slot)); val = ((0 << tpg_reg->tpg_num_frames_shift_val) | - ((num_dts-1) << tpg_reg->tpg_num_dts_shift_val) | + ((num_dts-1) << tpg_reg->tpg_num_dts_shift_val) | stream->vc); cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_vc0_cfg0 + (0x60 * vc_slot)); @@ -320,7 +565,7 @@ static int configure_vc( cam_io_w_mb(hw->hw_info->shdr_overlap << tpg_reg->tpg_overlap_shdr_en_shift, soc_info->reg_map[0].mem_base + tpg_reg->tpg_ctrl); } - if (hw->hw_info->shdr_offset_num_batch >= 0 && vc_slot > 0) { + if (hw->hw_info->shdr_offset_num_batch >= 0 && vc_slot > 0) { val = (VC1_GAIN << tpg_reg->tpg_gain_shift); val |= (hw->hw_info->shdr_offset_num_batch << tpg_reg->tpg_shdr_offset_num_batch_shift); @@ -336,7 +581,6 @@ static int configure_vc( hw->hw_idx, vc_slot, val); } - return 0; } @@ -391,32 +635,60 @@ int tpg_hw_v_1_3_process_cmd( switch(cmd) { case TPG_CONFIG_VC: { - struct vc_config_args *vc_config = - (struct vc_config_args *)arg; + if (hw->stream_version == 1) { + struct vc_config_args *vc_config = + (struct vc_config_args *)arg; - if (vc_config == NULL) { - CAM_ERR(CAM_TPG, "invalid argument"); - return -EINVAL; + if (vc_config == NULL) { + CAM_ERR(CAM_TPG, "invalid argument"); + return -EINVAL; + } + rc = configure_vc(hw, + vc_config->vc_slot, + vc_config->num_dts, + vc_config->stream); + } else if (hw->stream_version == 3) { + struct vc_config_args_v3 *vc_config_v3 = + (struct vc_config_args_v3 *)arg; + + if (vc_config_v3 == NULL) { + CAM_ERR(CAM_TPG, "invalid argument"); + return -EINVAL; + } + rc = configure_vc_v3(hw, + vc_config_v3->vc_slot, + vc_config_v3->num_dts, + vc_config_v3->stream); } - rc = configure_vc(hw, - vc_config->vc_slot, - vc_config->num_dts, - vc_config->stream); } break; case TPG_CONFIG_DT: { - struct dt_config_args *dt_config = - (struct dt_config_args *)arg; + if (hw->stream_version == 1) { + struct dt_config_args *dt_config = + (struct dt_config_args *)arg; - if (dt_config == NULL) { - CAM_ERR(CAM_TPG, "invalid argument"); - return -EINVAL; + if (dt_config == NULL) { + CAM_ERR(CAM_TPG, "invalid argument"); + return -EINVAL; + } + rc = configure_dt(hw, + dt_config->vc_slot, + dt_config->dt_slot, + dt_config->stream); + } else if (hw->stream_version == 3) { + struct dt_config_args_v3 *dt_config_v3 = + (struct dt_config_args_v3 *)arg; + + if (dt_config_v3 == NULL) { + CAM_ERR(CAM_TPG, "invalid argument"); + return -EINVAL; + } + rc = configure_dt_v3(hw, + dt_config_v3->vc_slot, + dt_config_v3->dt_slot, + dt_config_v3->stream); } - rc = configure_dt(hw, - dt_config->vc_slot, - dt_config->dt_slot, - dt_config->stream); } break; case TPG_CONFIG_CTRL: diff --git a/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3_data.h b/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3_data.h index 193024f5c2..ea72def2cc 100644 --- a/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3_data.h +++ b/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw_v_1_3/tpg_hw_v_1_3_data.h @@ -35,7 +35,7 @@ struct tpg_hw_info tpg_v_1_3_hw_info = { }; struct tpg_hw_info tpg_v_1_3_1_hw_info = { - .version = TPG_HW_VERSION_1_3, + .version = TPG_HW_VERSION_1_3_1, .max_vc_channels = 4, .max_dt_channels_per_vc = 4, .ops = &tpg_hw_v_1_3_ops, diff --git a/include/uapi/camera/media/cam_sensor.h b/include/uapi/camera/media/cam_sensor.h index 03c4e47ef1..f645867218 100644 --- a/include/uapi/camera/media/cam_sensor.h +++ b/include/uapi/camera/media/cam_sensor.h @@ -163,6 +163,33 @@ enum tpg_phy_type_t { TPG_PHY_TYPE_MAX, }; +enum tpg_pixel_type_t { + TPG_PIXEL_TYPE_INVALID = 0, + TPG_PIXEL_TYPE_RED, + TPG_PIXEL_TYPE_GREEN, + TPG_PIXEL_TYPE_BLUE, + TPG_PIXEL_TYPE_IR, + TPG_PIXEL_TYPE_MONO, +}; + +enum tpg_exposure_type_t { + TPG_EXPOSUREL_TYPE_INVALID = 0, + TPG_EXPOSURE_TYPE_LONG, + TPG_EXPOSURE_TYPE_MIDDLE, + TPG_EXPOSURE_TYPE_SHORT, +}; + +enum xcfa_type_t { + XCFA_TYPE_BAYER = 0, + XCFA_TYPE_QUADCFA, + XCFA_TYPE_THREEXTHREECFA, + XCFA_TYPE_FOURXFOURCFA, + XCFA_TYPE_RGBIR, + XCFA_TYPE_RGBWC, + XCFA_TYPE_RGBWK, + XCFA_TYPE_UNCONVENTIONAL_BAYER, +}; + enum tpg_interleaving_format_t { TPG_INTERLEAVING_FORMAT_INVALID = 0, TPG_INTERLEAVING_FORMAT_FRAME, @@ -738,6 +765,37 @@ struct tpg_command_header_t { uint32_t cmd_version; } __attribute__((packed)); +/** + * tpg_pixel_coordinate_t : pixel coordinate structure + * + * @xcoordinate : X coordinate + * @ycoordinate : Y coordiante + * @pixel_type : red green blue ir mono + */ +struct tpg_pixel_coordinate_t { + uint32_t xcoordinate; + uint32_t ycoordinate; + uint32_t exposure_type; + uint32_t pixel_type; +} __attribute__((packed)); + +/** + * tpg_cfa_information_t : tpg cfa information structure + * + * @number_of_pixel_per_color : number of pixel per color + * @pattern_width : pattern width + * @pattern_height : pattern height + * @pixel_coordinate_count : pixel coordinate count + * @pixel_coordinate : pixel coordinate array + */ +struct tpg_cfa_information_t { + uint32_t number_of_pixel_per_color; + uint32_t pattern_width; + uint32_t pattern_height; + uint32_t pixel_coordinate_count; + struct tpg_pixel_coordinate_t pixel_coordinate[64]; +} __attribute__((packed)); + /** * tpg_global_config_t : global configuration command structure * @@ -769,6 +827,45 @@ struct tpg_global_config_t { uint32_t reserved[4]; } __attribute__((packed)); +/** + * tpg_old_stream_config_t : stream configuration command + * + * @header: common tpg command header + * @pattern_type : tpg pattern type used in this stream + * @cb_mode : tpg color bar mode used in this stream + * @frame_count : frame count in case of trigger burst mode + * @stream_type : type of stream like image pdaf etc + * @stream_dimension : Dimension of the stream + * @pixel_depth : bits per each pixel + * @cfa_arrangement : color filter arragement + * @output_format : output image format + * @hbi : horizontal blanking intervel + * @vbi : vertical blanking intervel + * @vc : virtual channel of this stream + * @dt : data type of this stream + * @skip_pattern : skip pattern for this stream + * @rotate_period : rotate period for this stream + * @reserved : reserved for future use + */ +struct tpg_old_stream_config_t { + struct tpg_command_header_t header; + enum tpg_pattern_t pattern_type; + enum tpg_color_bar_mode_t cb_mode; + uint32_t frame_count; + enum tpg_stream_t stream_type; + struct stream_dimension stream_dimension; + uint8_t pixel_depth; + enum tpg_cfa_arrangement_t cfa_arrangement; + enum tpg_image_format_t output_format; + uint32_t hbi; + uint32_t vbi; + uint16_t vc; + uint16_t dt; + uint32_t skip_pattern; + uint32_t rotate_period; + uint32_t reserved[4]; +} __attribute__((packed)); + /** * tpg_stream_config_t : stream configuration command * @@ -786,10 +883,11 @@ struct tpg_global_config_t { * @vc : virtual channel of this stream * @dt : data type of this stream * @skip_pattern : skip pattern for this stream + * @rotate_period : rotate period for this stream * @xcfa_debug : for xcfa debug; * @shdr_line_offset0 : for shdr line offset0 * @shdr_line_offset1 : for shdr line offset1 - * @reserved : reserved for future use + * @reserved : reserved for future use */ struct tpg_stream_config_t { struct tpg_command_header_t header; @@ -813,6 +911,56 @@ struct tpg_stream_config_t { uint32_t reserved[4]; } __attribute__((packed)); +/** + * tpg_stream_config_t : stream configuration command + * + * @header: common tpg command header + * @pattern_type : tpg pattern type used in this stream + * @cb_mode : tpg color bar mode used in this stream + * @frame_count : frame count in case of trigger burst mode + * @stream_type : type of stream like image pdaf etc + * @stream_dimension : Dimension of the stream + * @pixel_depth : bits per each pixel + * @cfa_arrangement : color filter arragement + * @output_format : output image format + * @hbi : horizontal blanking intervel + * @vbi : vertical blanking intervel + * @vc : virtual channel of this stream + * @dt : data type of this stream + * @skip_pattern : skip pattern for this stream + * @rotate_period : rotate period for this stream + * @shdr_line_offset0 : for shdr line offset0 + * @shdr_line_offset1 : for shdr line offset1 + * @cfa_info_exist : cfa info exists + * @cfa_info : cfa information + * @xcfa_type : xcfa type + * @reserved : reserved for future use + */ +struct tpg_stream_config_v3_t { + struct tpg_command_header_t header; + uint32_t pattern_type; + uint32_t cb_mode; + uint32_t frame_count; + uint32_t stream_type; + struct stream_dimension stream_dimension; + uint32_t pixel_depth; + uint32_t cfa_arrangement; + uint32_t output_format; + uint32_t hbi; + uint32_t vbi; + uint16_t vc; + uint16_t dt; + uint32_t skip_pattern; + uint32_t rotate_period; + uint32_t xcfa_debug; + uint32_t shdr_line_offset0; + uint32_t shdr_line_offset1; + uint32_t cfa_info_exist; + struct tpg_cfa_information_t cfa_info; + uint32_t xcfa_type; + uint32_t reserved[5]; +} __attribute__((packed)); + /** * tpg_illumination_control : illumianation control command *