diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index bac9233ed5..a88b247baa 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -651,6 +651,7 @@ struct cam_hw_inject_evt_param { * @hw_dump: Function pointer for HW dump * @hw_recovery: Function pointer for HW recovery callback * @hw_inject_evt: Function pointer for HW event injection callback + * @synx_trigger: Function pointer for synx test trigger * */ struct cam_hw_mgr_intf { @@ -676,6 +677,7 @@ struct cam_hw_mgr_intf { int (*hw_dump)(void *hw_priv, void *hw_dump_args); int (*hw_recovery)(void *hw_priv, void *hw_recovery_args); void (*hw_inject_evt)(void *hw_priv, void *evt_args); + int (*synx_trigger)(void *hw_priv, void *synx_params); }; #endif /* _CAM_HW_MGR_INTF_H_ */ diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index b5fc6a6f02..cc768ae720 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.c @@ -736,6 +736,26 @@ int cam_node_shutdown(struct cam_node *node) return 0; } +static int __cam_node_handle_synx_test( + struct cam_node *node, void *params) +{ + int i, rc = -EINVAL; + + for (i = 0; i < node->ctx_size; i++) { + if (node->ctx_list[i].dev_hdl > 0) { + CAM_ERR(CAM_CORE, "Node [%s] has active context [%d]", + node->name, i); + return -EAGAIN; + } + } + + if (node->hw_mgr_intf.synx_trigger) + rc = node->hw_mgr_intf.synx_trigger( + node->hw_mgr_intf.hw_mgr_priv, params); + + return rc; +} + int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf, struct cam_context *ctx_list, uint32_t ctx_size, char *name) { @@ -1030,6 +1050,21 @@ release_kfree: } break; } + case CAM_SYNX_TEST_TRIGGER: { + struct cam_synx_test_params synx_params; + + if (copy_from_user(&synx_params, u64_to_user_ptr(cmd->handle), + sizeof(synx_params))) { + rc = -EFAULT; + break; + } + + rc = __cam_node_handle_synx_test(node, &synx_params); + if (rc) + CAM_ERR(CAM_CORE, "Synx test on %s failed(rc = %d)", + node->name, rc); + break; + } default: CAM_ERR(CAM_CORE, "Unknown op code %d", cmd->op_code); rc = -EINVAL; diff --git a/drivers/cam_icp/fw_inc/hfi_session_defs.h b/drivers/cam_icp/fw_inc/hfi_session_defs.h index 1a753e52d5..f39a128c1c 100644 --- a/drivers/cam_icp/fw_inc/hfi_session_defs.h +++ b/drivers/cam_icp/fw_inc/hfi_session_defs.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_HFI_SESSION_DEFS_H @@ -595,4 +595,23 @@ struct hfi_msg_ipe_frame_process { uint64_t user_data; } __packed; +/** + * struct hfi_cmd_synx_test_payload + * Same struct used for cmd and response + * + * @size: Size of the pkt + * @pkt_type: pkt type (cmd/response) + * @input_size: Input buffer size + * @input_iova: Input buffer address + * @output_size: Output buffer size + * @output_iova: Output buffer address + */ +struct hfi_cmd_synx_test_payload { + uint32_t size; + uint32_t pkt_type; + uint32_t input_size; + uint32_t input_iova; + uint32_t output_size; + uint32_t output_iova; +} __packed; #endif /* _CAM_HFI_SESSION_DEFS_H */ diff --git a/drivers/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/cam_icp/fw_inc/hfi_sys_defs.h index 924e279e6f..f08d3532d9 100644 --- a/drivers/cam_icp/fw_inc/hfi_sys_defs.h +++ b/drivers/cam_icp/fw_inc/hfi_sys_defs.h @@ -122,6 +122,7 @@ #define HFI_CMD_DBG_COMMON_START \ (HFI_DOMAIN_BASE_DBG + HFI_CMD_START_OFFSET + 0x0) #define HFI_CMD_DBG_TEST_START (HFI_CMD_DBG_COMMON_START + 0x800) +#define HFI_CMD_DBG_SYNX_TEST (HFI_CMD_DBG_TEST_START + 0x1) #define HFI_CMD_DBG_END (HFI_CMD_DBG_COMMON_START + 0xFFF) /* System level messages */ @@ -192,8 +193,10 @@ /* ICP core level Debug test message range */ #define HFI_MSG_DBG_COMMON_START \ - (HFI_DOMAIN_BASE_DBG + 0x0) + (HFI_DOMAIN_BASE_DBG + HFI_MSG_START_OFFSET + 0x0) + #define HFI_MSG_DBG_TEST_START (HFI_MSG_DBG_COMMON_START + 0x800) +#define HFI_MSG_DBG_SYNX_TEST (HFI_MSG_DBG_TEST_START + 0x1) #define HFI_MSG_DBG_END (HFI_MSG_DBG_COMMON_START + 0xFFF) /* System level property base offset */ diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 1732b39596..a668c2c9a8 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -3070,6 +3070,11 @@ static int cam_icp_process_msg_pkt_type( break; + case HFI_MSG_DBG_SYNX_TEST: + CAM_DBG(CAM_ICP, "received DBG_SYNX_TEST"); + size_processed = sizeof(struct hfi_cmd_synx_test_payload); + complete(&hw_mgr->icp_complete); + break; default: CAM_ERR(CAM_ICP, "[%s] invalid msg : %u", hw_mgr->hw_mgr_name, msg_ptr[ICP_PACKET_TYPE]); @@ -3969,7 +3974,6 @@ static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr) bool send_freq_info = true; CAM_DBG(CAM_PERF, "[%s] ENTER", hw_mgr->hw_mgr_name); - if (!icp_dev_intf) { CAM_ERR(CAM_ICP, "[%s] ICP device interface is NULL", hw_mgr->hw_mgr_name); return -EINVAL; @@ -6600,6 +6604,137 @@ static int cam_icp_mgr_hw_dump(void *hw_priv, void *hw_dump_args) return rc; } +static int cam_icp_mgr_synx_core_control( + struct cam_icp_hw_mgr *hw_mgr, + struct cam_synx_core_control *synx_core_ctrl) +{ + int rc; + + if (synx_core_ctrl->core_control) { + rc = cam_icp_mgr_icp_resume(hw_mgr); + if (!rc) + /* Set FW log level for synx */ + if (hw_mgr->icp_debug_type) + hfi_set_debug_level(hw_mgr->hfi_handle, + hw_mgr->icp_debug_type, hw_mgr->icp_dbg_lvl); + } else { + rc = cam_icp_mgr_icp_power_collapse(hw_mgr); + } + + if (rc) + CAM_ERR(CAM_ICP, "[%s] Failed to process core control resume: %s", + hw_mgr->hw_mgr_name, CAM_BOOL_TO_YESNO(synx_core_ctrl->core_control)); + + CAM_INFO(CAM_ICP, "Synx test core control: %s done rc: %d", + CAM_BOOL_TO_YESNO(synx_core_ctrl->core_control), rc); + return rc; +} + +static int cam_icp_mgr_synx_send_test_cmd( + struct cam_icp_hw_mgr *hw_mgr, + struct cam_synx_test_cmd *synx_test_params) +{ + int rc = 0; + size_t size; + dma_addr_t iova; + struct hfi_cmd_synx_test_payload synx_test_cmd; + unsigned long rem_jiffies; + int timeout = 5000; + + if (!hw_mgr->icp_resumed) { + rc = cam_icp_mgr_icp_resume(hw_mgr); + if (rc) { + CAM_ERR(CAM_ICP, "Failed to resume ICP rc: %d", rc); + goto end; + } + + /* Set FW log level for synx */ + if (hw_mgr->icp_debug_type) + hfi_set_debug_level(hw_mgr->hfi_handle, + hw_mgr->icp_debug_type, hw_mgr->icp_dbg_lvl); + } + + synx_test_cmd.pkt_type = HFI_CMD_DBG_SYNX_TEST; + synx_test_cmd.size = sizeof(synx_test_cmd); + + rc = cam_mem_get_io_buf(synx_test_params->ip_mem_hdl, hw_mgr->iommu_hdl, + &iova, &size, NULL); + if (rc) { + CAM_ERR(CAM_ICP, "Failed to get buf for hdl: %d rc: %d", + synx_test_params->ip_mem_hdl, rc); + goto end; + } + + synx_test_cmd.input_iova = (uint32_t)iova; + synx_test_cmd.input_size = (uint32_t)size; + + rc = cam_mem_get_io_buf(synx_test_params->op_mem_hdl, hw_mgr->iommu_hdl, + &iova, &size, NULL); + if (rc) { + CAM_ERR(CAM_ICP, "Failed to get buf for hdl: %d rc: %d", + synx_test_params->ip_mem_hdl, rc); + goto end; + } + + synx_test_cmd.output_iova = (uint32_t)iova; + synx_test_cmd.output_size = (uint32_t)size; + + CAM_DBG(CAM_ICP, + "Input (hdl: 0x%x iova: 0x%x size: 0x%x) output (hdl: 0x%x iova: 0x%x size: 0x%x)", + synx_test_params->ip_mem_hdl, synx_test_cmd.input_iova, synx_test_cmd.input_size, + synx_test_params->op_mem_hdl, synx_test_cmd.output_iova, synx_test_cmd.output_size); + + reinit_completion(&hw_mgr->icp_complete); + rc = hfi_write_cmd(hw_mgr->hfi_handle, &synx_test_cmd); + if (rc) + goto end; + + rem_jiffies = CAM_COMMON_WAIT_FOR_COMPLETION_TIMEOUT_ERRMSG( + &hw_mgr->icp_complete, msecs_to_jiffies(timeout), CAM_ICP, + "FW response timeout for synx test cmd"); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + goto end; + } + + CAM_INFO(CAM_ICP, "Synx test cmd done rc: %d", rc); + +end: + return rc; +} + +static int cam_icp_mgr_service_synx_test_cmds(void *hw_priv, void *synx_args) +{ + int rc; + struct cam_icp_hw_mgr *hw_mgr = hw_priv; + struct cam_synx_test_params *synx_params; + + if ((!hw_priv) || (!synx_args)) { + CAM_ERR(CAM_ICP, "Input params are Null:"); + return -EINVAL; + } + + synx_params = (struct cam_synx_test_params *)synx_args; + mutex_lock(&hw_mgr->hw_mgr_mutex); + switch (synx_params->cmd_type) { + case CAM_SYNX_TEST_CMD_TYPE_CORE_CTRL: { + rc = cam_icp_mgr_synx_core_control(hw_mgr, &synx_params->u.core_ctrl); + } + break; + case CAM_SYNX_TEST_CMD_TYPE_SYNX_CMD: { + rc = cam_icp_mgr_synx_send_test_cmd(hw_mgr, &synx_params->u.test_cmd); + } + break; + default: + rc = -EINVAL; + goto end; + } + +end: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; @@ -8007,6 +8142,7 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, hw_mgr_intf->hw_inject_evt = cam_icp_mgr_inject_evt; hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE; hw_mgr->mini_dump_cb = mini_dump_cb; + hw_mgr_intf->synx_trigger = cam_icp_mgr_service_synx_test_cmds; mutex_init(&hw_mgr->hw_mgr_mutex); spin_lock_init(&hw_mgr->hw_mgr_lock); diff --git a/include/uapi/camera/media/cam_defs.h b/include/uapi/camera/media/cam_defs.h index 4ff707a589..a974ba5a14 100644 --- a/include/uapi/camera/media/cam_defs.h +++ b/include/uapi/camera/media/cam_defs.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __UAPI_CAM_DEFS_H__ @@ -30,6 +30,7 @@ #define CAM_RELEASE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x2) #define CAM_DUMP_REQ (CAM_COMMON_OPCODE_BASE_v2 + 0x3) #define CAM_QUERY_CAP_V3 (CAM_COMMON_OPCODE_BASE_v2 + 0x4) +#define CAM_SYNX_TEST_TRIGGER (CAM_COMMON_OPCODE_BASE_v2 + 0x5) #define CAM_EXT_OPCODE_BASE 0x200 #define CAM_CONFIG_DEV_EXTERNAL (CAM_EXT_OPCODE_BASE + 0x1) @@ -258,6 +259,10 @@ struct cam_iommu_handle { /* constants */ #define CAM_PACKET_MAX_PLANES 3 +/* synx test cmd types */ +#define CAM_SYNX_TEST_CMD_TYPE_CORE_CTRL 1 +#define CAM_SYNX_TEST_CMD_TYPE_SYNX_CMD 2 + /** * struct cam_plane_cfg - Plane configuration info * @@ -907,4 +912,73 @@ struct cam_dump_req_cmd { __s32 dev_handle; }; +/** + * struct cam_synx_test_cmd - Synx test cmds + * + * @version: Struct version + * @ip_mem_hdl: Input buf mem handle + * corresponds to synx test inputs to the + * fencing core + * @op_mem_hdl: Output buf mem handle + * corresponds to synx output generated by + * the fencing core + * @num_valid_params: Num valid params + * @valid_param_mask: Valid param mask + * @params: additional params + */ +struct cam_synx_test_cmd { + __u32 version; + __s32 ip_mem_hdl; + __s32 op_mem_hdl; + __u32 num_valid_params; + __u32 valid_param_mask; + __u32 params[5]; +}; + +/** + * struct cam_synx_core_control - Synx core ctrl + * + * @version: Struct version + * @core_control: Set for resume, unset for collapse + * @num_valid_params: Num valid params + * @valid_param_mask: Valid param mask + * @params: additional params + */ +struct cam_synx_core_control { + __u32 version; + __u32 core_control; + __u32 num_valid_params; + __u32 valid_param_mask; + __u32 params[4]; +}; + + +/** + * struct cam_synx_test_params - Synx test params + * + * A test sequence could include creating and signaling + * synx handle between ICP <-> APPs. These test params + * would be cmds such as session initialize, synx create, + * synx async wait, synx signal and so on + * + * @version: Struct version + * @cmd_type: Type of test cmd - core control/synx cmd/... + * @num_valid_params: Num valid params + * @valid_param_mask: Valid param mask + * @params: additional params + * @test_cmd: Synx test cmd forwarded to the core + * @core_ctrl: Synx test cmd to control fencing core + */ +struct cam_synx_test_params { + __u32 version; + __u32 cmd_type; + __u32 num_valid_params; + __u32 valid_param_mask; + __u32 params[4]; + union { + struct cam_synx_test_cmd test_cmd; + struct cam_synx_core_control core_ctrl; + } u; +} __attribute__((__packed__)); + #endif /* __UAPI_CAM_DEFS_H__ */